Adjust settings and optimize theme styles

This commit is contained in:
ShirkNeko
2025-05-30 20:00:33 +08:00
parent 253276a27b
commit 6405764df3
6 changed files with 18 additions and 345 deletions

View File

@@ -1,18 +1,19 @@
package com.sukisu.ultra.ui.component package com.sukisu.ultra.ui.component
import androidx.compose.foundation.LocalIndication import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.background
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.selection.toggleable import androidx.compose.foundation.selection.toggleable
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.Role
import com.dergoogler.mmrl.ui.component.LabelItem import com.dergoogler.mmrl.ui.component.LabelItem
@@ -85,20 +86,4 @@ fun SwitchItem(
} }
} }
) )
}
@Composable
fun RadioItem(
title: String,
selected: Boolean,
onClick: () -> Unit,
) {
ListItem(
headlineContent = {
Text(title)
},
leadingContent = {
RadioButton(selected = selected, onClick = onClick)
}
)
} }

View File

@@ -479,7 +479,7 @@ fun MoreSettingsScreen(navigator: DestinationsNavigator) {
) )
} }
val cardColor = MaterialTheme.colorScheme.surfaceContainerLow val cardColor = MaterialTheme.colorScheme.surfaceContainerHigh
val cardAlphaUse = CardConfig.cardAlpha val cardAlphaUse = CardConfig.cardAlpha
val isDarkTheme = isSystemInDarkTheme() val isDarkTheme = isSystemInDarkTheme()

View File

@@ -59,13 +59,14 @@ import com.sukisu.ultra.*
import com.sukisu.ultra.ui.component.* import com.sukisu.ultra.ui.component.*
import com.sukisu.ultra.ui.theme.* import com.sukisu.ultra.ui.theme.*
import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
import com.sukisu.ultra.ui.util.LocalSnackbarHost import com.sukisu.ultra.ui.util.LocalSnackbarHost
import com.sukisu.ultra.ui.util.getBugreportFile import com.sukisu.ultra.ui.util.getBugreportFile
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import com.sukisu.ultra.ui.component.KsuIsValid import com.sukisu.ultra.ui.component.KsuIsValid
import com.dergoogler.mmrl.platform.Platform import com.dergoogler.mmrl.platform.Platform
import com.dergoogler.mmrl.ui.component.LabelItem
import com.dergoogler.mmrl.ui.component.text.TextRow
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@@ -119,9 +120,9 @@ fun SettingScreen(navigator: DestinationsNavigator) {
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp), .padding(horizontal = 16.dp, vertical = 8.dp),
colors = CardDefaults.cardColors( colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceContainerLow.copy(alpha = cardAlpha) containerColor = MaterialTheme.colorScheme.surfaceContainerHigh.copy(alpha = cardAlpha)
), ),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation) elevation = CardDefaults.cardElevation(defaultElevation = 0.dp)
) { ) {
Column(modifier = Modifier.padding(vertical = 8.dp)) { Column(modifier = Modifier.padding(vertical = 8.dp)) {
Text( Text(
@@ -192,9 +193,9 @@ fun SettingScreen(navigator: DestinationsNavigator) {
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp), .padding(horizontal = 16.dp, vertical = 8.dp),
colors = CardDefaults.cardColors( colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceContainerLow.copy(alpha = cardAlpha) containerColor = MaterialTheme.colorScheme.surfaceContainerHigh.copy(alpha = cardAlpha)
), ),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation) elevation = CardDefaults.cardElevation(defaultElevation = 0.dp)
) { ) {
Column(modifier = Modifier.padding(vertical = 8.dp)) { Column(modifier = Modifier.padding(vertical = 8.dp)) {
Text( Text(
@@ -306,9 +307,9 @@ fun SettingScreen(navigator: DestinationsNavigator) {
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp), .padding(horizontal = 16.dp, vertical = 8.dp),
colors = CardDefaults.cardColors( colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceContainerLow.copy(alpha = cardAlpha) containerColor = MaterialTheme.colorScheme.surfaceContainerHigh.copy(alpha = cardAlpha)
), ),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation) elevation = CardDefaults.cardElevation(defaultElevation = 0.dp)
) { ) {
Column(modifier = Modifier.padding(vertical = 8.dp)) { Column(modifier = Modifier.padding(vertical = 8.dp)) {
Text( Text(
@@ -399,15 +400,15 @@ fun SettingScreen(navigator: DestinationsNavigator) {
} }
} }
// 设置分组卡片 - 关于 // 关于
Card( Card(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp), .padding(horizontal = 16.dp, vertical = 8.dp),
colors = CardDefaults.cardColors( colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceContainerLow.copy(alpha = cardAlpha) containerColor = MaterialTheme.colorScheme.surfaceContainerHigh.copy(alpha = cardAlpha)
), ),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation) elevation = CardDefaults.cardElevation(defaultElevation = 0.dp)
) { ) {
Column(modifier = Modifier.padding(vertical = 8.dp)) { Column(modifier = Modifier.padding(vertical = 8.dp)) {
Text( Text(
@@ -504,7 +505,6 @@ fun SettingItem(
) )
} }
} }
Icon( Icon(
imageVector = Icons.Filled.ChevronRight, imageVector = Icons.Filled.ChevronRight,
contentDescription = null, contentDescription = null,

View File

@@ -1,273 +0,0 @@
package com.sukisu.ultra.ui.webui
import androidx.activity.ComponentActivity
import androidx.activity.SystemBarStyle
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
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.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.paint
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.zIndex
import android.os.Build
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.updateTransition
import androidx.compose.ui.graphics.graphicsLayer
import coil.compose.AsyncImagePainter
import coil.compose.rememberAsyncImagePainter
import com.sukisu.ultra.ui.theme.ThemeConfig
import com.sukisu.ultra.ui.theme.Typography
import com.sukisu.ultra.ui.theme.loadCustomBackground
// 提供界面类型的本地组合
val LocalIsSecondaryScreen = staticCompositionLocalOf { false }
/**
* WebUI专用主题配置
*/
@Composable
fun WebUIXTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
dynamicColor: Boolean = true,
isSecondaryScreen: Boolean = false,
content: @Composable () -> Unit
) {
val context = LocalContext.current
LaunchedEffect(Unit) {
if (!ThemeConfig.backgroundImageLoaded && !ThemeConfig.preventBackgroundRefresh) {
context.loadCustomBackground()
ThemeConfig.backgroundImageLoaded = false
}
}
// 更新二级界面状态
LaunchedEffect(isSecondaryScreen) {
WebViewInterface.updateSecondaryScreenState(isSecondaryScreen)
}
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
if (darkTheme) {
dynamicDarkColorScheme(context).let { scheme ->
if (isSecondaryScreen) {
scheme.copy(
background = scheme.surfaceContainerHighest,
surface = scheme.surfaceContainerHighest
)
} else {
scheme.copy(
background = Color.Transparent,
surface = Color.Transparent
)
}
}
} else {
dynamicLightColorScheme(context).let { scheme ->
if (isSecondaryScreen) {
scheme.copy(
background = scheme.surfaceContainerHighest,
surface = scheme.surfaceContainerHighest
)
} else {
scheme.copy(
background = Color.Transparent,
surface = Color.Transparent
)
}
}
}
}
darkTheme -> {
if (isSecondaryScreen) {
darkColorScheme().copy(
background = MaterialTheme.colorScheme.surfaceContainerHighest,
surface = MaterialTheme.colorScheme.surfaceContainerHighest
)
} else {
darkColorScheme().copy(
background = Color.Transparent,
surface = Color.Transparent
)
}
}
else -> {
if (isSecondaryScreen) {
lightColorScheme().copy(
background = MaterialTheme.colorScheme.surfaceContainerHighest,
surface = MaterialTheme.colorScheme.surfaceContainerHighest
)
} else {
lightColorScheme().copy(
background = Color.Transparent,
surface = Color.Transparent
)
}
}
}
ConfigureSystemBars(darkTheme)
val backgroundUri = remember { mutableStateOf(ThemeConfig.customBackgroundUri) }
LaunchedEffect(ThemeConfig.customBackgroundUri) {
backgroundUri.value = ThemeConfig.customBackgroundUri
}
val bgImagePainter = backgroundUri.value?.let {
rememberAsyncImagePainter(
model = it,
onError = {
ThemeConfig.backgroundImageLoaded = false
},
onSuccess = {
ThemeConfig.backgroundImageLoaded = true
ThemeConfig.isThemeChanging = false
}
)
}
// 背景透明度动画
val transition = updateTransition(
targetState = ThemeConfig.backgroundImageLoaded,
label = "bgTransition"
)
val bgAlpha by transition.animateFloat(
label = "bgAlpha",
transitionSpec = {
spring(
dampingRatio = 0.8f,
stiffness = 300f
)
}
) { loaded -> if (loaded) 1f else 0f }
CompositionLocalProvider(LocalIsSecondaryScreen provides isSecondaryScreen) {
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
) {
if (isSecondaryScreen) {
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.surfaceContainerHighest)
) {
content()
}
} else {
Box(modifier = Modifier.fillMaxSize()) {
Box(
modifier = Modifier
.fillMaxSize()
.zIndex(-2f)
.background(if (darkTheme) Color.Black else Color.White)
)
backgroundUri.value?.let { uri ->
Box(
modifier = Modifier
.fillMaxSize()
.zIndex(-1f)
.alpha(bgAlpha)
) {
bgImagePainter?.let { painter ->
Box(
modifier = Modifier
.fillMaxSize()
.paint(
painter = painter,
contentScale = ContentScale.Crop
)
.graphicsLayer {
alpha = (painter.state as? AsyncImagePainter.State.Success)?.let { 1f } ?: 0f
}
)
}
Box(
modifier = Modifier
.fillMaxSize()
.background(
if (darkTheme) Color.Black.copy(alpha = 0.6f)
else Color.White.copy(alpha = 0.1f)
)
)
Box(
modifier = Modifier
.fillMaxSize()
.background(
Brush.radialGradient(
colors = listOf(
Color.Transparent,
if (darkTheme) Color.Black.copy(alpha = 0.5f)
else Color.Black.copy(alpha = 0.2f)
),
radius = 1200f
)
)
)
}
}
Box(
modifier = Modifier
.fillMaxSize()
.zIndex(1f)
) {
content()
}
}
}
}
}
}
/**
* 配置WebUI的系统栏样式
*/
@Composable
private fun ConfigureSystemBars(
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()
)
}
)
}
}

View File

@@ -20,6 +20,7 @@ import com.dergoogler.mmrl.ui.component.Loading
import com.dergoogler.mmrl.webui.screen.WebUIScreen import com.dergoogler.mmrl.webui.screen.WebUIScreen
import com.dergoogler.mmrl.webui.util.rememberWebUIOptions import com.dergoogler.mmrl.webui.util.rememberWebUIOptions
import com.sukisu.ultra.BuildConfig import com.sukisu.ultra.BuildConfig
import com.sukisu.ultra.ui.theme.KernelSUTheme
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -68,7 +69,7 @@ class WebUIXActivity : ComponentActivity() {
val prefs = getSharedPreferences("settings", MODE_PRIVATE) val prefs = getSharedPreferences("settings", MODE_PRIVATE)
setContent { setContent {
WebUIXTheme { KernelSUTheme {
var isLoading by remember { mutableStateOf(true) } var isLoading by remember { mutableStateOf(true) }
LaunchedEffect(Platform.isAlive) { LaunchedEffect(Platform.isAlive) {
@@ -81,7 +82,7 @@ class WebUIXActivity : ComponentActivity() {
if (isLoading) { if (isLoading) {
Loading() Loading()
return@WebUIXTheme return@KernelSUTheme
} }
val webDebugging = prefs.getBoolean("enable_web_debugging", false) val webDebugging = prefs.getBoolean("enable_web_debugging", false)

View File

@@ -7,9 +7,6 @@ import android.text.TextUtils
import android.view.Window import android.view.Window
import android.webkit.JavascriptInterface import android.webkit.JavascriptInterface
import android.widget.Toast import android.widget.Toast
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat import androidx.core.view.WindowInsetsControllerCompat
import com.dergoogler.mmrl.webui.interfaces.WXInterface import com.dergoogler.mmrl.webui.interfaces.WXInterface
@@ -23,8 +20,7 @@ import com.sukisu.ultra.ui.util.listModules
import com.sukisu.ultra.ui.util.withNewRootShell import com.sukisu.ultra.ui.util.withNewRootShell
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import com.sukisu.ultra.ui.util.controlKpmModule import com.sukisu.ultra.ui.util.*
import com.sukisu.ultra.ui.util.listKpmModules
import java.io.File import java.io.File
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
@@ -34,47 +30,11 @@ class WebViewInterface(
override var name: String = "ksu" override var name: String = "ksu"
companion object { companion object {
private var isSecondaryScreenState by mutableStateOf(false)
private var windowInsetsController: WindowInsetsControllerCompat? = null
fun factory() = JavaScriptInterface(WebViewInterface::class.java) fun factory() = JavaScriptInterface(WebViewInterface::class.java)
fun updateSecondaryScreenState(isSecondary: Boolean) {
isSecondaryScreenState = isSecondary
windowInsetsController?.let { controller ->
if (isSecondary) {
controller.show(WindowInsetsCompat.Type.systemBars())
controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_DEFAULT
} else {
controller.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
}
}
fun setWindowInsetsController(controller: WindowInsetsControllerCompat) {
windowInsetsController = controller
}
} }
init {
if (context is Activity) {
setWindowInsetsController(WindowInsetsControllerCompat(
activity.window,
activity.window.decorView
))
}
}
private val modDir get() = "/data/adb/modules/${modId.id}" private val modDir get() = "/data/adb/modules/${modId.id}"
@JavascriptInterface
fun isSecondaryPage(): Boolean {
return isSecondaryScreenState
}
@JavascriptInterface @JavascriptInterface
fun exec(cmd: String): String { fun exec(cmd: String): String {
return withNewRootShell(true) { ShellUtils.fastCmd(this, cmd) } return withNewRootShell(true) { ShellUtils.fastCmd(this, cmd) }