manager: continue to improve the UI

- Expose anykernel3 flashing as long as there is root.
- Opt some styles
This commit is contained in:
ShirkNeko
2025-05-04 14:19:29 +08:00
parent cb90630f27
commit d06f22dcd0
16 changed files with 893 additions and 436 deletions

View File

@@ -32,6 +32,8 @@ import com.sukisu.ultra.ui.screen.BottomBarDestination
import com.sukisu.ultra.ui.theme.*
import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha
import com.sukisu.ultra.ui.util.*
import androidx.core.content.edit
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
class MainActivity : ComponentActivity() {
private inner class ThemeChangeContentObserver(
@@ -45,7 +47,6 @@ class MainActivity : ComponentActivity() {
}
override fun onCreate(savedInstanceState: Bundle?) {
// Enable edge to edge
enableEdgeToEdge()
@@ -55,8 +56,18 @@ class MainActivity : ComponentActivity() {
super.onCreate(savedInstanceState)
val prefs = getSharedPreferences("settings", MODE_PRIVATE)
val isFirstRun = prefs.getBoolean("is_first_run", true)
if (isFirstRun) {
ThemeConfig.preventBackgroundRefresh = false
getSharedPreferences("theme_prefs", MODE_PRIVATE).edit {
putBoolean("prevent_background_refresh", false)
}
prefs.edit { putBoolean("is_first_run", false) }
}
// 加载保存的背景设置
loadCustomBackground()
loadThemeMode()
loadThemeColors()
loadDynamicColorState()
@@ -64,10 +75,12 @@ class MainActivity : ComponentActivity() {
val contentObserver = ThemeChangeContentObserver(Handler(mainLooper)) {
runOnUiThread {
if (!ThemeConfig.preventBackgroundRefresh) {
ThemeConfig.backgroundImageLoaded = false
loadCustomBackground()
}
}
}
contentResolver.registerContentObserver(
android.provider.Settings.System.getUriFor("ui_night_mode"),
@@ -115,6 +128,22 @@ class MainActivity : ComponentActivity() {
}
}
override fun onPause() {
super.onPause()
CardConfig.save(applicationContext)
getSharedPreferences("theme_prefs", MODE_PRIVATE).edit() {
putBoolean("prevent_background_refresh", true)
}
ThemeConfig.preventBackgroundRefresh = true
}
override fun onResume() {
super.onResume()
if (!ThemeConfig.backgroundImageLoaded && !ThemeConfig.preventBackgroundRefresh) {
loadCustomBackground()
}
}
private val destroyListeners = mutableListOf<() -> Unit>()
override fun onDestroy() {
@@ -141,7 +170,7 @@ private fun BottomBar(navController: NavHostController) {
containerColor = cardColor.copy(alpha = cardAlpha),
scrolledContainerColor = containerColor.copy(alpha = cardAlpha)
).containerColor,
tonalElevation = 0.dp
tonalElevation = cardElevation
) {
BottomBarDestination.entries.forEach { destination ->
if (destination == BottomBarDestination.Kpm) {
@@ -169,7 +198,6 @@ private fun BottomBar(navController: NavHostController) {
destination.iconNotSelected
},
contentDescription = stringResource(destination.label),
tint = if (isCurrentDestOnBackStack) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
)
},
label = {

View File

@@ -63,7 +63,7 @@ fun SearchAppBar(
var onSearch by remember { mutableStateOf(false) }
// 获取卡片颜色和透明度
val cardColor = MaterialTheme.colorScheme.secondaryContainer
val cardColor = MaterialTheme.colorScheme.surfaceVariant
val cardAlpha = CardConfig.cardAlpha
if (onSearch) {

View File

@@ -1,7 +1,13 @@
package com.sukisu.ultra.ui.screen
import android.annotation.SuppressLint
import androidx.annotation.StringRes
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.Crossfade
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.BoxWithConstraints
@@ -25,16 +31,21 @@ import androidx.compose.material.icons.filled.Android
import androidx.compose.material.icons.filled.Security
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilterChip
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarColors
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
@@ -44,7 +55,10 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.pointerInput
@@ -63,13 +77,13 @@ import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplateScreenDestination
import com.ramcosta.composedestinations.generated.destinations.TemplateEditorScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import com.sukisu.ultra.Natives
import com.sukisu.ultra.R
import com.sukisu.ultra.ui.component.SwitchItem
import com.sukisu.ultra.ui.component.profile.AppProfileConfig
import com.sukisu.ultra.ui.component.profile.RootProfileConfig
import com.sukisu.ultra.ui.component.profile.TemplateConfig
import com.sukisu.ultra.ui.theme.CardConfig
import com.sukisu.ultra.ui.util.LocalSnackbarHost
import com.sukisu.ultra.ui.util.forceStopApp
import com.sukisu.ultra.ui.util.getSepolicy
@@ -78,6 +92,7 @@ import com.sukisu.ultra.ui.util.restartApp
import com.sukisu.ultra.ui.util.setSepolicy
import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel
import com.sukisu.ultra.ui.viewmodel.getTemplateInfoById
import kotlinx.coroutines.launch
/**
* @author weishu
@@ -107,9 +122,18 @@ fun AppProfileScreen(
mutableStateOf(initialProfile)
}
val cardColor = MaterialTheme.colorScheme.surfaceVariant
val cardAlpha = CardConfig.cardAlpha
Scaffold(
topBar = {
TopBar(
title = appInfo.label,
packageName = packageName,
colors = TopAppBarDefaults.topAppBarColors(
containerColor = cardColor.copy(alpha = cardAlpha),
scrolledContainerColor = cardColor.copy(alpha = cardAlpha)
),
onBack = dropUnlessResumed { navigator.popBackStack() },
scrollBehavior = scrollBehavior
)
@@ -181,22 +205,50 @@ private fun AppProfileInner(
val isRootGranted = profile.allowSu
Column(modifier = modifier) {
ElevatedCard(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
shape = MaterialTheme.shapes.medium
) {
AppMenuBox(packageName) {
ListItem(
headlineContent = { Text(appLabel) },
supportingContent = { Text(packageName) },
headlineContent = {
Text(
text = appLabel,
style = MaterialTheme.typography.titleMedium
)
},
supportingContent = {
Text(
text = packageName,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
},
leadingContent = appIcon,
)
}
}
ElevatedCard(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
shape = MaterialTheme.shapes.medium
) {
SwitchItem(
icon = Icons.Filled.Security,
title = stringResource(id = R.string.superuser),
checked = isRootGranted,
onCheckedChange = { onProfileChange(profile.copy(allowSu = it)) },
)
}
Crossfade(targetState = isRootGranted, label = "") { current ->
Crossfade(
targetState = isRootGranted,
label = "RootAccess"
) { current ->
Column(
modifier = Modifier.padding(bottom = 6.dp + 48.dp + 6.dp /* SnackBar height */)
) {
@@ -211,6 +263,13 @@ private fun AppProfileInner(
var mode by rememberSaveable {
mutableStateOf(initialMode)
}
ElevatedCard(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
shape = MaterialTheme.shapes.medium
) {
ProfileBox(mode, true) {
// template mode shouldn't change profile here!
if (it == Mode.Default || it == Mode.Custom) {
@@ -218,33 +277,73 @@ private fun AppProfileInner(
}
mode = it
}
Crossfade(targetState = mode, label = "") { currentMode ->
if (currentMode == Mode.Template) {
}
AnimatedVisibility(
visible = mode != Mode.Default,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
ElevatedCard(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
shape = MaterialTheme.shapes.medium
) {
Column(modifier = Modifier.padding(vertical = 8.dp)) {
Crossfade(targetState = mode, label = "ProfileMode") { currentMode ->
when (currentMode) {
Mode.Template -> {
TemplateConfig(
profile = profile,
onViewTemplate = onViewTemplate,
onManageTemplate = onManageTemplate,
onProfileChange = onProfileChange
)
} else if (mode == Mode.Custom) {
}
Mode.Custom -> {
RootProfileConfig(
fixedName = true,
profile = profile,
onProfileChange = onProfileChange
)
}
else -> {}
}
}
}
}
}
} else {
val mode = if (profile.nonRootUseDefault) Mode.Default else Mode.Custom
ElevatedCard(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
shape = MaterialTheme.shapes.medium
) {
ProfileBox(mode, false) {
onProfileChange(profile.copy(nonRootUseDefault = (it == Mode.Default)))
}
Crossfade(targetState = mode, label = "") { currentMode ->
val modifyEnabled = currentMode == Mode.Custom
}
AnimatedVisibility(
visible = mode == Mode.Custom,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
ElevatedCard(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
shape = MaterialTheme.shapes.medium
) {
Column(modifier = Modifier.padding(vertical = 8.dp)) {
AppProfileConfig(
fixedName = true,
profile = profile,
enabled = modifyEnabled,
enabled = mode == Mode.Custom,
onProfileChange = onProfileChange
)
}
@@ -252,6 +351,8 @@ private fun AppProfileInner(
}
}
}
}
}
}
private enum class Mode(@StringRes private val res: Int) {
@@ -264,20 +365,51 @@ private enum class Mode(@StringRes private val res: Int) {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(
title: String,
packageName: String,
onBack: () -> Unit,
colors: TopAppBarColors,
scrollBehavior: TopAppBarScrollBehavior? = null
) {
TopAppBar(
title = {
Text(stringResource(R.string.profile))
Column {
Text(
text = title,
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurface
)
Text(
text = packageName,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.alpha(0.8f)
)
}
},
colors = colors,
navigationIcon = {
IconButton(
onClick = onBack
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }
onClick = onBack,
colors = IconButtonDefaults.iconButtonColors(
contentColor = MaterialTheme.colorScheme.onSurface
)
) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = stringResource(R.string.back)
)
}
},
windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
scrollBehavior = scrollBehavior
windowInsets = WindowInsets.safeDrawing.only(
WindowInsetsSides.Top + WindowInsetsSides.Horizontal
),
scrollBehavior = scrollBehavior,
modifier = Modifier.shadow(
elevation = if ((scrollBehavior?.state?.overlappedFraction ?: 0f) > 0.01f)
4.dp else 0.dp,
spotColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.1f)
)
)
}
@@ -287,40 +419,88 @@ private fun ProfileBox(
hasTemplate: Boolean,
onModeChange: (Mode) -> Unit,
) {
Column(modifier = Modifier.padding(vertical = 8.dp)) {
ListItem(
headlineContent = { Text(stringResource(R.string.profile)) },
supportingContent = { Text(mode.text) },
leadingContent = { Icon(Icons.Filled.AccountCircle, null) },
headlineContent = {
Text(
text = stringResource(R.string.profile),
style = MaterialTheme.typography.titleMedium
)
HorizontalDivider(thickness = Dp.Hairline)
ListItem(headlineContent = {
},
supportingContent = {
Text(
text = mode.text,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
},
leadingContent = {
Icon(
imageVector = Icons.Filled.AccountCircle,
contentDescription = null,
)
},
)
HorizontalDivider(
thickness = Dp.Hairline,
color = MaterialTheme.colorScheme.outlineVariant
)
ListItem(
headlineContent = {
Row(
modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally)
) {
FilterChip(
selected = mode == Mode.Default,
label = { Text(stringResource(R.string.profile_default)) },
onClick = { onModeChange(Mode.Default) },
label = {
Text(
text = stringResource(R.string.profile_default),
style = MaterialTheme.typography.bodyMedium
)
},
shape = MaterialTheme.shapes.small
)
if (hasTemplate) {
FilterChip(
selected = mode == Mode.Template,
label = { Text(stringResource(R.string.profile_template)) },
onClick = { onModeChange(Mode.Template) },
label = {
Text(
text = stringResource(R.string.profile_template),
style = MaterialTheme.typography.bodyMedium
)
},
shape = MaterialTheme.shapes.small
)
}
FilterChip(
selected = mode == Mode.Custom,
label = { Text(stringResource(R.string.profile_custom)) },
onClick = { onModeChange(Mode.Custom) },
label = {
Text(
text = stringResource(R.string.profile_custom),
style = MaterialTheme.typography.bodyMedium
)
},
shape = MaterialTheme.shapes.small
)
}
}
)
}
})
}
@SuppressLint("UnusedBoxWithConstraintsScope")
@Composable
private fun AppMenuBox(packageName: String, content: @Composable () -> Unit) {
var expanded by remember { mutableStateOf(false) }
var touchPoint: Offset by remember { mutableStateOf(Offset.Zero) }
val density = LocalDensity.current
@@ -329,13 +509,14 @@ private fun AppMenuBox(packageName: String, content: @Composable () -> Unit) {
Modifier
.fillMaxSize()
.pointerInput(Unit) {
detectTapGestures {
detectTapGestures(
onLongPress = {
touchPoint = it
expanded = true
}
)
}
) {
content()
val (offsetX, offsetY) = with(density) {
@@ -349,43 +530,64 @@ private fun AppMenuBox(packageName: String, content: @Composable () -> Unit) {
expanded = false
},
) {
DropdownMenuItem(
text = { Text(stringResource(id = R.string.launch_app)) },
AppMenuOption(
text = stringResource(id = R.string.launch_app),
onClick = {
expanded = false
launchApp(packageName)
},
}
)
DropdownMenuItem(
text = { Text(stringResource(id = R.string.force_stop_app)) },
AppMenuOption(
text = stringResource(id = R.string.force_stop_app),
onClick = {
expanded = false
forceStopApp(packageName)
},
}
)
DropdownMenuItem(
text = { Text(stringResource(id = R.string.restart_app)) },
AppMenuOption(
text = stringResource(id = R.string.restart_app),
onClick = {
expanded = false
restartApp(packageName)
},
}
)
}
}
}
@Composable
private fun AppMenuOption(text: String, onClick: () -> Unit) {
DropdownMenuItem(
text = {
Text(
text = text,
style = MaterialTheme.typography.bodyMedium
)
},
onClick = onClick
)
}
@Preview
@Composable
private fun AppProfilePreview() {
var profile by remember { mutableStateOf(Natives.Profile("")) }
Surface {
AppProfileInner(
packageName = "icu.nullptr.test",
appLabel = "Test",
appIcon = { Icon(Icons.Filled.Android, null) },
appIcon = {
Icon(
imageVector = Icons.Filled.Android,
contentDescription = null,
)
},
profile = profile,
onProfileChange = {
profile = it
},
)
}
}

View File

@@ -34,12 +34,10 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Android
import androidx.compose.material.icons.filled.Archive
import androidx.compose.material.icons.filled.Code
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.Memory
import androidx.compose.material.icons.filled.PhoneAndroid
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.School
import androidx.compose.material.icons.filled.Security
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.filled.Storage
@@ -99,6 +97,7 @@ import com.sukisu.ultra.getKernelVersion
import com.sukisu.ultra.ksuApp
import com.sukisu.ultra.ui.component.rememberConfirmDialog
import com.sukisu.ultra.ui.theme.CardConfig
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
import com.sukisu.ultra.ui.theme.getCardColors
import com.sukisu.ultra.ui.util.checkNewVersion
import com.sukisu.ultra.ui.util.getKpmModuleCount
@@ -245,11 +244,11 @@ fun HomeScreen(navigator: DestinationsNavigator) {
) {
ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.secondaryContainer),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier
.clip(MaterialTheme.shapes.medium)
.shadow(
elevation = 0.dp,
elevation = cardElevation,
shape = MaterialTheme.shapes.medium,
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)
)
@@ -267,7 +266,6 @@ fun HomeScreen(navigator: DestinationsNavigator) {
Icon(
imageVector = Icons.Outlined.Info,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(end = 12.dp)
)
Text(
@@ -365,7 +363,6 @@ fun RebootDropdownItem(@StringRes id: Int, reason: String = "") {
Icon(
imageVector = Icons.Filled.Refresh,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary
)
}
)
@@ -393,12 +390,11 @@ private fun TopBar(
scrolledContainerColor = cardColor.copy(alpha = cardAlpha)
),
actions = {
if (kernelVersion.isGKI()) {
if (rootAvailable() || kernelVersion.isGKI()) {
IconButton(onClick = onInstallClick) {
Icon(
Icons.Filled.Archive,
contentDescription = stringResource(R.string.install),
tint = MaterialTheme.colorScheme.primary
)
}
}
@@ -409,7 +405,6 @@ private fun TopBar(
Icon(
Icons.Filled.Refresh,
contentDescription = stringResource(R.string.reboot),
tint = MaterialTheme.colorScheme.primary
)
DropdownMenu(
@@ -444,22 +439,22 @@ private fun StatusCard(
onClickInstall: () -> Unit = {}
) {
ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHigh),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp),
colors = getCardColors(MaterialTheme.colorScheme.surfaceVariant),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier
.fillMaxWidth()
.clip(MaterialTheme.shapes.large)
.shadow(
elevation = 0.dp,
elevation = cardElevation,
shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)
spotColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.1f)
)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable(enabled = kernelVersion.isGKI()) {
if (kernelVersion.isGKI()) {
.clickable {
if (rootAvailable() || kernelVersion.isGKI()) {
onClickInstall()
}
}
@@ -620,12 +615,12 @@ fun WarningCard(
) {
ElevatedCard(
colors = getCardColors(color),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier
.fillMaxWidth()
.clip(MaterialTheme.shapes.large)
.shadow(
elevation = 0.dp,
elevation = cardElevation,
shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.error.copy(alpha = 0.1f)
)
@@ -660,14 +655,14 @@ fun ContributionCard() {
val links = listOf("https://github.com/zako", "https://github.com/udochina")
ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.tertiaryContainer),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp),
colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHigh),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.clip(MaterialTheme.shapes.large)
.shadow(
elevation = 0.dp,
elevation = cardElevation,
shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.tertiary.copy(alpha = 0.1f)
)
@@ -682,27 +677,18 @@ fun ContributionCard() {
.padding(24.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Filled.Code,
contentDescription = null,
tint = MaterialTheme.colorScheme.onTertiaryContainer,
modifier = Modifier
.padding(end = 16.dp)
.size(24.dp)
)
Column {
Text(
text = stringResource(R.string.home_ContributionCard_kernelsu),
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.onTertiaryContainer
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(Modifier.height(4.dp))
Text(
text = stringResource(R.string.home_click_to_ContributionCard_kernelsu),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onTertiaryContainer.copy(alpha = 0.8f)
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.8f)
)
}
}
@@ -715,13 +701,13 @@ fun LearnMoreCard() {
val url = stringResource(R.string.home_learn_kernelsu_url)
ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.primaryContainer),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp),
colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHigh),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier
.fillMaxWidth()
.clip(MaterialTheme.shapes.large)
.shadow(
elevation = 0.dp,
elevation = cardElevation,
shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)
)
@@ -735,27 +721,18 @@ fun LearnMoreCard() {
.padding(24.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Filled.School,
contentDescription = null,
tint = MaterialTheme.colorScheme.onPrimaryContainer,
modifier = Modifier
.padding(end = 16.dp)
.size(24.dp)
)
Column {
Text(
text = stringResource(R.string.home_learn_kernelsu),
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.onPrimaryContainer
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(Modifier.height(4.dp))
Text(
text = stringResource(R.string.home_click_to_learn_kernelsu),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.8f)
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.8f)
)
}
}
@@ -767,13 +744,13 @@ fun DonateCard() {
val uriHandler = LocalUriHandler.current
ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.secondaryContainer),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp),
colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHigh),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier
.fillMaxWidth()
.clip(MaterialTheme.shapes.large)
.shadow(
elevation = 0.dp,
elevation = cardElevation,
shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.secondary.copy(alpha = 0.1f)
)
@@ -787,27 +764,18 @@ fun DonateCard() {
.padding(24.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Filled.Favorite,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSecondaryContainer,
modifier = Modifier
.padding(end = 16.dp)
.size(24.dp)
)
Column {
Text(
text = stringResource(R.string.home_support_title),
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.onSecondaryContainer
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(Modifier.height(4.dp))
Text(
text = stringResource(R.string.home_support_content),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSecondaryContainer.copy(alpha = 0.8f)
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.8f)
)
}
}
@@ -823,12 +791,12 @@ private fun InfoCard() {
ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHighest),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier
.fillMaxWidth()
.clip(MaterialTheme.shapes.large)
.shadow(
elevation = 0.dp,
elevation = cardElevation,
shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.05f)
)
@@ -858,7 +826,7 @@ private fun InfoCard() {
imageVector = icon,
contentDescription = label,
modifier = Modifier.size(24.dp),
tint = MaterialTheme.colorScheme.primary
tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f),
)
Spacer(modifier = Modifier.width(16.dp))
Column(

View File

@@ -15,7 +15,14 @@ import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.verticalScroll
@@ -23,34 +30,71 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.AutoFixHigh
import androidx.compose.material.icons.filled.FileUpload
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.RadioButtonDefaults
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.maxkeppeker.sheets.core.models.base.Header
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
import com.maxkeppeler.sheets.list.ListDialog
import com.maxkeppeler.sheets.list.models.ListOption
import com.maxkeppeler.sheets.list.models.ListSelection
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import com.sukisu.ultra.R
import com.sukisu.ultra.flash.HorizonKernelFlashProgress
import com.sukisu.ultra.flash.HorizonKernelState
import com.sukisu.ultra.flash.HorizonKernelWorker
import com.sukisu.ultra.ui.component.DialogHandle
import com.sukisu.ultra.ui.component.SlotSelectionDialog
import com.sukisu.ultra.ui.component.rememberConfirmDialog
import com.sukisu.ultra.ui.component.rememberCustomDialog
import com.sukisu.ultra.flash.HorizonKernelFlashProgress
import com.sukisu.ultra.flash.HorizonKernelState
import com.sukisu.ultra.flash.HorizonKernelWorker
import com.sukisu.ultra.ui.theme.CardConfig
import com.sukisu.ultra.ui.theme.ThemeConfig
import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
import com.sukisu.ultra.ui.theme.getCardColors
import com.sukisu.ultra.ui.util.*
import com.sukisu.ultra.ui.util.LkmSelection
import com.sukisu.ultra.ui.util.getCurrentKmi
import com.sukisu.ultra.ui.util.getSupportedKmis
import com.sukisu.ultra.ui.util.isAbDevice
import com.sukisu.ultra.ui.util.isInitBoot
import com.sukisu.ultra.ui.util.rootAvailable
import com.sukisu.ultra.getKernelVersion
/**
* @author weishu
@@ -69,6 +113,8 @@ fun InstallScreen(navigator: DestinationsNavigator) {
val horizonKernelState = remember { HorizonKernelState() }
val flashState by horizonKernelState.state.collectAsState()
val summary = stringResource(R.string.horizon_kernel_summary)
val kernelVersion = getKernelVersion()
val isGKI = kernelVersion.isGKI()
val onFlashComplete = {
showRebootDialog = true
@@ -133,7 +179,6 @@ fun InstallScreen(navigator: DestinationsNavigator) {
summary = summary
)
installMethod = horizonMethod
onInstall()
}
)
@@ -149,7 +194,7 @@ fun InstallScreen(navigator: DestinationsNavigator) {
}
val onClickNext = {
if (lkmSelection == LkmSelection.KmiNone && currentKmi.isBlank()) {
if (isGKI && lkmSelection == LkmSelection.KmiNone && currentKmi.isBlank()) {
selectKmiDialog.show()
} else {
onInstall()
@@ -191,8 +236,10 @@ fun InstallScreen(navigator: DestinationsNavigator) {
.padding(innerPadding)
.nestedScroll(scrollBehavior.nestedScrollConnection)
.verticalScroll(rememberScrollState())
.padding(top = 12.dp)
) {
SelectInstallMethod(
isGKI = isGKI,
onSelected = { method ->
if (method is InstallMethod.HorizonKernel && method.uri != null && method.slot == null) {
tempKernelUri = method.uri
@@ -218,32 +265,73 @@ fun InstallScreen(navigator: DestinationsNavigator) {
.padding(16.dp)
) {
(lkmSelection as? LkmSelection.LkmUri)?.let {
ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.surfaceVariant),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 12.dp)
.clip(MaterialTheme.shapes.medium)
.shadow(
elevation = cardElevation,
shape = MaterialTheme.shapes.medium,
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)
)
) {
Text(
stringResource(
text = stringResource(
id = R.string.selected_lkm,
it.uri.lastPathSegment ?: "(file)"
)
),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(16.dp)
)
}
}
(installMethod as? InstallMethod.HorizonKernel)?.let { method ->
if (method.slot != null) {
ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.surfaceVariant),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 12.dp)
.clip(MaterialTheme.shapes.medium)
.shadow(
elevation = cardElevation,
shape = MaterialTheme.shapes.medium,
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)
)
) {
Text(
stringResource(
text = stringResource(
id = R.string.selected_slot,
if (method.slot == "a") stringResource(id = R.string.slot_a)
else stringResource(id = R.string.slot_b)
)
),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(16.dp)
)
}
}
}
Button(
modifier = Modifier.fillMaxWidth(),
enabled = installMethod != null && !flashState.isFlashing,
onClick = onClickNext
onClick = onClickNext,
shape = MaterialTheme.shapes.medium,
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.onPrimary,
disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.6f),
disabledContentColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f)
)
) {
Text(
stringResource(id = R.string.install_next),
fontSize = MaterialTheme.typography.bodyMedium.fontSize
style = MaterialTheme.typography.bodyMedium
)
}
}
@@ -305,7 +393,10 @@ sealed class InstallMethod {
}
@Composable
private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
private fun SelectInstallMethod(
isGKI: Boolean = false,
onSelected: (InstallMethod) -> Unit = {}
) {
val rootAvailable = rootAvailable()
val isAbDevice = isAbDevice()
val horizonKernelSummary = stringResource(R.string.horizon_kernel_summary)
@@ -393,21 +484,68 @@ private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
var LKMExpanded by remember { mutableStateOf(false) }
var GKIExpanded by remember { mutableStateOf(false) }
Column {
Column(
modifier = Modifier.padding(horizontal = 16.dp)
) {
// LKM 安装/修补
if (isGKI && rootAvailable) {
ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.surfaceVariant),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 12.dp)
.clip(MaterialTheme.shapes.large)
.shadow(
elevation = cardElevation,
shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)
)
) {
ListItem(
leadingContent = { Icon(Icons.Filled.AutoFixHigh, null) },
headlineContent = { Text(stringResource(R.string.Lkm_install_methods)) },
leadingContent = {
Icon(
Icons.Filled.AutoFixHigh,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary
)
},
headlineContent = {
Text(
stringResource(R.string.Lkm_install_methods),
style = MaterialTheme.typography.titleMedium
)
},
modifier = Modifier.clickable {
LKMExpanded = !LKMExpanded
}
)
radioOptions.take(3).forEach { option ->
AnimatedVisibility(
visible = LKMExpanded,
modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp)
enter = fadeIn() + expandVertically(),
exit = shrinkVertically() + fadeOut()
) {
Column {
Column(
modifier = Modifier.padding(
start = 16.dp,
end = 16.dp,
bottom = 16.dp
)
) {
radioOptions.take(3).forEach { option ->
val interactionSource = remember { MutableInteractionSource() }
Surface(
color = if (option.javaClass == selectedOption?.javaClass)
MaterialTheme.colorScheme.secondaryContainer.copy(alpha = cardAlpha)
else
MaterialTheme.colorScheme.surfaceContainerHighest.copy(alpha = cardAlpha),
shape = MaterialTheme.shapes.medium,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 4.dp)
.clip(MaterialTheme.shapes.medium)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
@@ -419,51 +557,102 @@ private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
indication = LocalIndication.current,
interactionSource = interactionSource
)
.padding(vertical = 8.dp, horizontal = 12.dp)
) {
RadioButton(
selected = option.javaClass == selectedOption?.javaClass,
onClick = { onClick(option) },
interactionSource = interactionSource
onClick = null,
interactionSource = interactionSource,
colors = RadioButtonDefaults.colors(
selectedColor = MaterialTheme.colorScheme.primary,
unselectedColor = MaterialTheme.colorScheme.onSurfaceVariant
)
)
Column(
modifier = Modifier.padding(vertical = 12.dp)
modifier = Modifier
.padding(start = 10.dp)
.weight(1f)
) {
Text(
text = stringResource(id = option.label),
fontSize = MaterialTheme.typography.titleMedium.fontSize,
fontFamily = MaterialTheme.typography.titleMedium.fontFamily,
fontStyle = MaterialTheme.typography.titleMedium.fontStyle
style = MaterialTheme.typography.bodyLarge
)
option.summary?.let {
Text(
text = it,
fontSize = MaterialTheme.typography.bodySmall.fontSize,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
fontStyle = MaterialTheme.typography.bodySmall.fontStyle
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
}
Spacer(modifier = Modifier.height(8.dp))
}
}
}
Column {
}
}
// anykernel3 刷写
if (rootAvailable) {
ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.surfaceVariant),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 12.dp)
.clip(MaterialTheme.shapes.large)
.shadow(
elevation = cardElevation,
shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)
)
) {
ListItem(
leadingContent = { Icon(Icons.Filled.FileUpload, null) },
headlineContent = { Text(stringResource(R.string.GKI_install_methods)) },
leadingContent = {
Icon(
Icons.Filled.FileUpload,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary
)
},
headlineContent = {
Text(
stringResource(R.string.GKI_install_methods),
style = MaterialTheme.typography.titleMedium
)
},
modifier = Modifier.clickable {
GKIExpanded = !GKIExpanded
}
)
AnimatedVisibility(
visible = GKIExpanded,
modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp)
enter = fadeIn() + expandVertically(),
exit = shrinkVertically() + fadeOut()
) {
Column {
Column(
modifier = Modifier.padding(
start = 16.dp,
end = 16.dp,
bottom = 16.dp
)
) {
if (radioOptions.size > 3) {
radioOptions.drop(3).forEach { option ->
val interactionSource = remember { MutableInteractionSource() }
Surface(
color = if (option.javaClass == selectedOption?.javaClass)
MaterialTheme.colorScheme.secondaryContainer.copy(alpha = cardAlpha)
else
MaterialTheme.colorScheme.surfaceContainerHighest.copy(alpha = cardAlpha),
shape = MaterialTheme.shapes.medium,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 4.dp)
.clip(MaterialTheme.shapes.medium)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
@@ -475,32 +664,76 @@ private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
indication = LocalIndication.current,
interactionSource = interactionSource
)
.padding(vertical = 8.dp, horizontal = 12.dp)
) {
RadioButton(
selected = option.javaClass == selectedOption?.javaClass,
onClick = { onClick(option) },
interactionSource = interactionSource
onClick = null,
interactionSource = interactionSource,
colors = RadioButtonDefaults.colors(
selectedColor = MaterialTheme.colorScheme.primary,
unselectedColor = MaterialTheme.colorScheme.onSurfaceVariant
)
)
Column(
modifier = Modifier.padding(vertical = 12.dp)
modifier = Modifier
.padding(start = 10.dp)
.weight(1f)
) {
Text(
text = stringResource(id = option.label),
fontSize = MaterialTheme.typography.titleMedium.fontSize,
fontFamily = MaterialTheme.typography.titleMedium.fontFamily,
fontStyle = MaterialTheme.typography.titleMedium.fontStyle
style = MaterialTheme.typography.bodyLarge
)
option.summary?.let {
Text(
text = it,
fontSize = MaterialTheme.typography.bodySmall.fontSize,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
fontStyle = MaterialTheme.typography.bodySmall.fontStyle
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
Spacer(modifier = Modifier.height(8.dp))
}
}
}
}
}
}
}
// 没有root
if (!rootAvailable) {
ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.errorContainer),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 12.dp)
.clip(MaterialTheme.shapes.large)
.shadow(
elevation = cardElevation,
shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.error.copy(alpha = 0.1f)
)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Filled.AutoFixHigh,
contentDescription = null,
tint = MaterialTheme.colorScheme.onErrorContainer,
modifier = Modifier
.padding(end = 16.dp)
)
Text(
text = stringResource(R.string.root_require_for_install),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onErrorContainer
)
}
}
}
@@ -514,77 +747,33 @@ fun rememberSelectKmiDialog(onSelected: (String?) -> Unit): DialogHandle {
val supportedKmi by produceState(initialValue = emptyList<String>()) {
value = getSupportedKmis()
}
val listOptions = supportedKmi.map { value ->
val options = supportedKmi.map { value ->
ListOption(
titleText = value,
subtitleText = null,
icon = null
titleText = value
)
}
var selection: String? = null
val cardColor = if (!ThemeConfig.useDynamicColor) {
ThemeConfig.currentTheme.ButtonContrast
} else {
MaterialTheme.colorScheme.secondaryContainer
}
var selection by remember { mutableStateOf<String?>(null) }
val backgroundColor = MaterialTheme.colorScheme.surfaceContainerHighest
AlertDialog(
onDismissRequest = {
dismiss()
},
title = {
Text(text = stringResource(R.string.select_kmi))
},
text = {
Column {
listOptions.forEachIndexed { index, option ->
Row(
modifier = Modifier
.clickable {
selection = supportedKmi[index]
}
.padding(vertical = 8.dp)
MaterialTheme(
colorScheme = MaterialTheme.colorScheme.copy(
surface = backgroundColor
)
) {
Column {
Text(text = option.titleText)
option.subtitleText?.let {
Text(
text = it,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
}
}
},
confirmButton = {
TextButton(
onClick = {
if (selection != null) {
ListDialog(state = rememberUseCaseState(visible = true, onFinishedRequest = {
onSelected(selection)
}
}, onCloseRequest = {
dismiss()
}), header = Header.Default(
title = stringResource(R.string.select_kmi),
), selection = ListSelection.Single(
showRadioButtons = true,
options = options,
) { _, option ->
selection = option.titleText
})
}
) {
Text(text = stringResource(android.R.string.ok))
}
},
dismissButton = {
TextButton(
onClick = {
dismiss()
}
) {
Text(text = stringResource(android.R.string.cancel))
}
},
containerColor = getCardColors(cardColor.copy(alpha = 0.9f)).containerColor.copy(alpha = 0.9f),
shape = MaterialTheme.shapes.medium,
tonalElevation = 0.dp
)
}
}
@@ -595,18 +784,26 @@ private fun TopBar(
onLkmUpload: () -> Unit = {},
scrollBehavior: TopAppBarScrollBehavior? = null
) {
val cardColor = MaterialTheme.colorScheme.secondaryContainer
val cardAlpha = CardConfig.cardAlpha
val cardColor = MaterialTheme.colorScheme.surfaceVariant
val cardAlpha = cardAlpha
TopAppBar(
title = { Text(stringResource(R.string.install)) },
title = {
Text(
stringResource(R.string.install),
style = MaterialTheme.typography.titleLarge
)
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = cardColor.copy(alpha = cardAlpha),
scrolledContainerColor = cardColor.copy(alpha = cardAlpha)
),
navigationIcon = {
IconButton(onClick = onBack) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = stringResource(R.string.back)
)
}
},
windowInsets = WindowInsets.safeDrawing.only(

View File

@@ -38,6 +38,7 @@ import java.io.FileInputStream
import java.io.InputStreamReader
import java.net.*
import android.app.Activity
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
/**
* KPM 管理界面
@@ -290,7 +291,6 @@ fun KpmScreen(
Icon(
imageVector = Icons.Filled.Refresh,
contentDescription = stringResource(R.string.refresh),
tint = MaterialTheme.colorScheme.primary
)
}
}
@@ -309,7 +309,6 @@ fun KpmScreen(
Icon(
imageVector = Icons.Filled.Add,
contentDescription = stringResource(R.string.kpm_install),
tint = MaterialTheme.colorScheme.onPrimaryContainer
)
},
text = {
@@ -346,7 +345,6 @@ fun KpmScreen(
Icon(
imageVector = Icons.Filled.Info,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSecondaryContainer,
modifier = Modifier
.padding(end = 16.dp)
.size(24.dp)
@@ -654,12 +652,12 @@ private fun KpmModuleItem(
Card(
colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHigh),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier
.fillMaxWidth()
.clip(MaterialTheme.shapes.large)
.shadow(
elevation = 0.dp,
elevation = cardElevation,
shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)
)

View File

@@ -71,6 +71,7 @@ import androidx.core.content.edit
import androidx.core.net.toUri
import com.sukisu.ultra.ui.theme.ThemeConfig
import com.sukisu.ultra.R
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
@OptIn(ExperimentalMaterial3Api::class)
@@ -233,7 +234,6 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
Icon(
imageVector = Icons.Filled.MoreVert,
contentDescription = stringResource(id = R.string.settings),
tint = MaterialTheme.colorScheme.primary
)
DropdownMenu(
@@ -294,7 +294,6 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
Icon(
imageVector = Icons.Outlined.Download,
contentDescription = stringResource(R.string.backup),
tint = MaterialTheme.colorScheme.primary
)
},
onClick = {
@@ -308,7 +307,6 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
Icon(
imageVector = Icons.Outlined.Refresh,
contentDescription = stringResource(R.string.restore),
tint = MaterialTheme.colorScheme.primary
)
},
onClick = {
@@ -343,7 +341,6 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
Icon(
imageVector = Icons.Filled.Add,
contentDescription = moduleInstall,
tint = MaterialTheme.colorScheme.onPrimaryContainer
)
},
text = {
@@ -690,12 +687,12 @@ fun ModuleItem(
) {
ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHigh),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp),
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier
.fillMaxWidth()
.clip(MaterialTheme.shapes.large)
.shadow(
elevation = 0.dp,
elevation = cardElevation,
shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)
)
@@ -919,7 +916,6 @@ fun ModuleItem(
modifier = Modifier.size(20.dp),
imageVector = Icons.Outlined.Delete,
contentDescription = null,
tint = MaterialTheme.colorScheme.onErrorContainer
)
} else {
Icon(

View File

@@ -307,11 +307,17 @@ fun MoreSettingsScreen(navigator: DestinationsNavigator) {
)
}
val cardColor = MaterialTheme.colorScheme.surfaceVariant
val cardAlphaUse = CardConfig.cardAlpha
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
TopAppBar(
title = { Text(stringResource(R.string.more_settings)) },
colors = TopAppBarDefaults.topAppBarColors(
containerColor = cardColor.copy(alpha = cardAlphaUse),
scrolledContainerColor = cardColor.copy(alpha = cardAlphaUse)),
navigationIcon = {
IconButton(onClick = { navigator.popBackStack() }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack,
@@ -395,7 +401,7 @@ fun MoreSettingsScreen(navigator: DestinationsNavigator) {
// 只在未启用动态颜色时显示主题色选择
AnimatedVisibility(
visible = !useDynamicColor,
visible = Build.VERSION.SDK_INT < Build.VERSION_CODES.S || !useDynamicColor,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
@@ -465,17 +471,25 @@ fun MoreSettingsScreen(navigator: DestinationsNavigator) {
} else {
context.saveCustomBackground(null)
isCustomBackgroundEnabled = false
CardConfig.cardElevation = CardConfig.defaultElevation
CardConfig.cardAlpha = 0.80f
CardConfig.cardElevation
CardConfig.cardAlpha = 1f
CardConfig.isCustomAlphaSet = false
CardConfig.isCustomBackgroundEnabled = false
saveCardConfig(context)
cardAlpha = 0.80f
cardAlpha = 1f
// 重置其他相关设置
ThemeConfig.needsResetOnThemeChange = true
ThemeConfig.preventBackgroundRefresh = false
context.getSharedPreferences("theme_prefs", Context.MODE_PRIVATE)
.edit {
putBoolean(
"prevent_background_refresh",
false
)
}
// 显示成功提示
Toast.makeText(
context,
context.getString(R.string.background_removed),
@@ -784,7 +798,7 @@ fun MoreSettingsScreen(navigator: DestinationsNavigator) {
CardConfig.isUserDarkModeEnabled = true
CardConfig.isUserLightModeEnabled = false
if (!CardConfig.isCustomAlphaSet) {
CardConfig.cardAlpha = 0.35f
CardConfig.cardAlpha = 1f
}
CardConfig.save(context)
}
@@ -793,7 +807,7 @@ fun MoreSettingsScreen(navigator: DestinationsNavigator) {
CardConfig.isUserLightModeEnabled = true
CardConfig.isUserDarkModeEnabled = false
if (!CardConfig.isCustomAlphaSet) {
CardConfig.cardAlpha = 0.80f
CardConfig.cardAlpha = 1f
}
CardConfig.save(context)
}

View File

@@ -52,6 +52,7 @@ import com.sukisu.ultra.*
import com.sukisu.ultra.ui.component.*
import com.sukisu.ultra.ui.theme.*
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.getBugreportFile
import java.time.LocalDateTime
@@ -117,7 +118,7 @@ fun SettingScreen(navigator: DestinationsNavigator) {
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceContainerLow.copy(alpha = cardAlpha)
),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp)
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation)
) {
Column(modifier = Modifier.padding(vertical = 8.dp)) {
Text(
@@ -190,7 +191,7 @@ fun SettingScreen(navigator: DestinationsNavigator) {
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceContainerLow.copy(alpha = cardAlpha)
),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp)
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation)
) {
Column(modifier = Modifier.padding(vertical = 8.dp)) {
Text(
@@ -258,7 +259,7 @@ fun SettingScreen(navigator: DestinationsNavigator) {
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceContainerLow.copy(alpha = cardAlpha)
),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp)
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation)
) {
Column(modifier = Modifier.padding(vertical = 8.dp)) {
Text(
@@ -357,7 +358,7 @@ fun SettingScreen(navigator: DestinationsNavigator) {
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceContainerLow.copy(alpha = cardAlpha)
),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp)
elevation = CardDefaults.cardElevation(defaultElevation = cardElevation)
) {
Column(modifier = Modifier.padding(vertical = 8.dp)) {
Text(
@@ -701,7 +702,7 @@ private fun TopBar(
val cardAlpha = if (ThemeConfig.customBackgroundUri != null) {
cardAlpha
} else {
if (systemIsDark) 0.35f else 0.80f
if (systemIsDark) 0.8f else 1f
}
TopAppBar(

View File

@@ -40,6 +40,7 @@ import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import com.sukisu.ultra.Natives
import com.sukisu.ultra.ui.component.SearchAppBar
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
import com.sukisu.ultra.ui.util.ModuleModify
import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel
@@ -87,7 +88,6 @@ fun SuperUserScreen(navigator: DestinationsNavigator) {
Icon(
imageVector = Icons.Filled.MoreVert,
contentDescription = stringResource(id = R.string.settings),
tint = MaterialTheme.colorScheme.primary
)
DropdownMenu(expanded = showDropdown, onDismissRequest = {
@@ -99,7 +99,6 @@ fun SuperUserScreen(navigator: DestinationsNavigator) {
Icon(
imageVector = Icons.Filled.Refresh,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary
)
},
onClick = {
@@ -124,7 +123,6 @@ fun SuperUserScreen(navigator: DestinationsNavigator) {
imageVector = if (viewModel.showSystemApps)
Icons.Filled.VisibilityOff else Icons.Filled.Visibility,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary
)
},
onClick = {
@@ -139,7 +137,6 @@ fun SuperUserScreen(navigator: DestinationsNavigator) {
Icon(
imageVector = Icons.Filled.Save,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary
)
},
onClick = {
@@ -153,7 +150,6 @@ fun SuperUserScreen(navigator: DestinationsNavigator) {
Icon(
imageVector = Icons.Filled.RestoreFromTrash,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary
)
},
onClick = {
@@ -178,8 +174,8 @@ fun SuperUserScreen(navigator: DestinationsNavigator) {
) {
Surface(
color = MaterialTheme.colorScheme.surfaceContainerHighest,
tonalElevation = 0.dp,
shadowElevation = 0.dp
tonalElevation = cardElevation,
shadowElevation = cardElevation
) {
Row(
modifier = Modifier

View File

@@ -33,6 +33,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarColors
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
@@ -61,6 +62,7 @@ import com.ramcosta.composedestinations.result.getOr
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import com.sukisu.ultra.R
import com.sukisu.ultra.ui.theme.CardConfig
import com.sukisu.ultra.ui.theme.ThemeConfig
import com.sukisu.ultra.ui.viewmodel.TemplateViewModel
@@ -98,6 +100,9 @@ fun AppProfileTemplateScreen(
}
}
val cardColorUse = MaterialTheme.colorScheme.surfaceVariant
val cardAlpha = CardConfig.cardAlpha
Scaffold(
topBar = {
val context = LocalContext.current
@@ -109,6 +114,10 @@ fun AppProfileTemplateScreen(
}
TopBar(
onBack = dropUnlessResumed { navigator.popBackStack() },
colors = TopAppBarDefaults.topAppBarColors(
containerColor = cardColorUse.copy(alpha = cardAlpha),
scrolledContainerColor = cardColorUse.copy(alpha = cardAlpha)
),
onSync = {
scope.launch { viewModel.fetchTemplates(true) }
},
@@ -226,12 +235,20 @@ private fun TopBar(
onSync: () -> Unit = {},
onImport: () -> Unit = {},
onExport: () -> Unit = {},
colors: TopAppBarColors,
scrollBehavior: TopAppBarScrollBehavior? = null
) {
val cardColor = MaterialTheme.colorScheme.surfaceVariant
val cardAlpha = CardConfig.cardAlpha
TopAppBar(
title = {
Text(stringResource(R.string.settings_profile_template))
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = cardColor.copy(alpha = cardAlpha),
scrolledContainerColor = cardColor.copy(alpha = cardAlpha)
),
navigationIcon = {
IconButton(
onClick = onBack

View File

@@ -13,10 +13,11 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
object CardConfig {
val defaultElevation: Dp = 1.dp
val settingElevation: Dp = 4.dp
val customBackgroundElevation: Dp = 0.dp
var cardAlpha by mutableStateOf(0.80f)
var cardElevation by mutableStateOf(defaultElevation)
var cardAlpha by mutableStateOf(1f)
var cardElevation by mutableStateOf(settingElevation)
var isShadowEnabled by mutableStateOf(true)
var isCustomAlphaSet by mutableStateOf(false)
var isUserDarkModeEnabled by mutableStateOf(false)
@@ -44,13 +45,13 @@ object CardConfig {
*/
fun load(context: Context) {
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
cardAlpha = prefs.getFloat("card_alpha", 0.80f)
cardAlpha = prefs.getFloat("card_alpha", 1f)
isCustomBackgroundEnabled = prefs.getBoolean("custom_background_enabled", false)
isShadowEnabled = prefs.getBoolean("is_shadow_enabled", true)
cardElevation = if (isShadowEnabled) defaultElevation else 0.dp
isCustomAlphaSet = prefs.getBoolean("is_custom_alpha_set", false)
isUserDarkModeEnabled = prefs.getBoolean("is_user_dark_mode_enabled", false)
isUserLightModeEnabled = prefs.getBoolean("is_user_light_mode_enabled", false)
updateShadowEnabled(isShadowEnabled)
}
/**
@@ -58,7 +59,13 @@ object CardConfig {
*/
fun updateShadowEnabled(enabled: Boolean) {
isShadowEnabled = enabled
cardElevation = if (enabled) defaultElevation else 0.dp
cardElevation = if (isCustomBackgroundEnabled && cardAlpha != 1f) {
customBackgroundElevation
} else if (enabled) {
settingElevation
} else {
customBackgroundElevation
}
}
/**
@@ -66,11 +73,9 @@ object CardConfig {
*/
fun setDarkModeDefaults() {
if (!isCustomAlphaSet) {
cardAlpha = 0.50f
}
if (!isShadowEnabled) {
cardElevation = 0.dp
cardAlpha = 1f
}
updateShadowEnabled(isShadowEnabled)
}
}

View File

@@ -56,6 +56,8 @@ object ThemeConfig {
var backgroundImageLoaded by mutableStateOf(false)
var needsResetOnThemeChange by mutableStateOf(false)
var isThemeChanging by mutableStateOf(false)
var preventBackgroundRefresh by mutableStateOf(false)
private var lastDarkModeState: Boolean? = null
fun detectThemeChange(currentDarkMode: Boolean): Boolean {
val isChanged = lastDarkModeState != null && lastDarkModeState != currentDarkMode
@@ -64,7 +66,9 @@ object ThemeConfig {
}
fun resetBackgroundState() {
if (!preventBackgroundRefresh) {
backgroundImageLoaded = false
}
isThemeChanging = true
}
}
@@ -92,14 +96,14 @@ fun KernelSUTheme(
Log.d("ThemeSystem", "系统主题变化检测: 从 ${!systemIsDark} 变为 $systemIsDark")
ThemeConfig.resetBackgroundState()
// 强制重新加载自定义背景
if (!ThemeConfig.preventBackgroundRefresh) {
context.loadCustomBackground()
}
// 调整卡片样式以适应新主题
CardConfig.apply {
load(context)
if (!isCustomAlphaSet) {
cardAlpha = if (systemIsDark) 0.35f else 0.80f
cardAlpha = if (systemIsDark) 0.50f else 1f
}
save(context)
}
@@ -108,16 +112,20 @@ fun KernelSUTheme(
// 初始加载配置
LaunchedEffect(Unit) {
context.loadCustomBackground()
context.loadThemeMode()
context.loadThemeColors()
context.loadDynamicColorState()
context.loadThemeMode()
CardConfig.load(context)
// 立即将加载状态设为false确保首次会触发加载动画
if (!ThemeConfig.backgroundImageLoaded && !ThemeConfig.preventBackgroundRefresh) {
context.loadCustomBackground()
ThemeConfig.backgroundImageLoaded = false
}
ThemeConfig.preventBackgroundRefresh = context.getSharedPreferences("theme_prefs", Context.MODE_PRIVATE)
.getBoolean("prevent_background_refresh", true)
}
// 创建颜色方案
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
@@ -134,15 +142,12 @@ fun KernelSUTheme(
}
CardConfig.updateShadowEnabled(!isDarkModeWithCustomBackground)
// 使用rememberSaveable保留背景URI状态防止在主题切换时丢失
val backgroundUri = rememberSaveable { mutableStateOf(ThemeConfig.customBackgroundUri) }
// 确保状态同步
LaunchedEffect(ThemeConfig.customBackgroundUri) {
backgroundUri.value = ThemeConfig.customBackgroundUri
}
// 背景图加载器 - 使用保存的URI状态
val bgImagePainter = backgroundUri.value?.let {
rememberAsyncImagePainter(
model = it,
@@ -155,11 +160,14 @@ fun KernelSUTheme(
Log.d("ThemeSystem", "背景图加载成功")
ThemeConfig.backgroundImageLoaded = true
ThemeConfig.isThemeChanging = false
ThemeConfig.preventBackgroundRefresh = true
context.getSharedPreferences("theme_prefs", Context.MODE_PRIVATE)
.edit { putBoolean("prevent_background_refresh", true) }
}
)
}
// 背景透明度动画 - 使用更强健的动画配置
val transition = updateTransition(
targetState = ThemeConfig.backgroundImageLoaded,
label = "bgTransition"
@@ -174,7 +182,6 @@ fun KernelSUTheme(
}
) { loaded -> if (loaded) 1f else 0f }
// 清理函数,确保主题切换完成后重置状态
DisposableEffect(systemIsDark) {
onDispose {
if (ThemeConfig.isThemeChanging) {
@@ -188,7 +195,6 @@ fun KernelSUTheme(
typography = Typography
) {
Box(modifier = Modifier.fillMaxSize()) {
// 底色层 - 确保有底色
Box(
modifier = Modifier
.fillMaxSize()
@@ -346,15 +352,18 @@ private fun createLightColorScheme() = lightColorScheme(
)
/**
* 复制图片到应用内部存储
* 复制图片到应用内部存储并提升持久性
*/
private fun Context.copyImageToInternalStorage(uri: Uri): Uri? {
return try {
val contentResolver: ContentResolver = contentResolver
val inputStream: InputStream = contentResolver.openInputStream(uri) ?: return null
val fileName = "custom_background.jpg"
val file = File(filesDir, fileName)
val outputStream = FileOutputStream(file)
val backupFile = File(filesDir, "${fileName}.backup")
val outputStream = FileOutputStream(backupFile)
val buffer = ByteArray(4 * 1024)
var read: Int
@@ -366,6 +375,11 @@ private fun Context.copyImageToInternalStorage(uri: Uri): Uri? {
outputStream.close()
inputStream.close()
if (file.exists()) {
file.delete()
}
backupFile.renameTo(file)
Uri.fromFile(file)
} catch (e: Exception) {
Log.e("ImageCopy", "复制图片失败: ${e.message}")
@@ -383,13 +397,17 @@ fun Context.saveAndApplyCustomBackground(uri: Uri, transformation: BackgroundTra
copyImageToInternalStorage(uri)
}
// 保存到配置文件
getSharedPreferences("theme_prefs", Context.MODE_PRIVATE)
.edit {
putString("custom_background", finalUri?.toString())
// 设置阻止刷新标志为false允许新设置的背景加载一次
putBoolean("prevent_background_refresh", false)
}
ThemeConfig.customBackgroundUri = finalUri
ThemeConfig.backgroundImageLoaded = false
ThemeConfig.preventBackgroundRefresh = false
CardConfig.cardElevation = 0.dp
CardConfig.isCustomBackgroundEnabled = true
}
@@ -399,13 +417,23 @@ fun Context.saveAndApplyCustomBackground(uri: Uri, transformation: BackgroundTra
*/
fun Context.saveCustomBackground(uri: Uri?) {
val newUri = uri?.let { copyImageToInternalStorage(it) }
// 保存到配置文件
getSharedPreferences("theme_prefs", Context.MODE_PRIVATE)
.edit {
putString("custom_background", newUri?.toString())
if (uri == null) {
// 如果清除背景,也重置阻止刷新标志
putBoolean("prevent_background_refresh", false)
} else {
// 设置阻止刷新标志为false允许新设置的背景加载一次
putBoolean("prevent_background_refresh", false)
}
}
ThemeConfig.customBackgroundUri = newUri
ThemeConfig.backgroundImageLoaded = false
ThemeConfig.preventBackgroundRefresh = false
if (uri != null) {
CardConfig.cardElevation = 0.dp
@@ -420,10 +448,14 @@ fun Context.loadCustomBackground() {
val uriString = getSharedPreferences("theme_prefs", Context.MODE_PRIVATE)
.getString("custom_background", null)
// 判断是否有实际变化,避免无谓的重新加载
val newUri = uriString?.toUri()
if (ThemeConfig.customBackgroundUri?.toString() != newUri?.toString()) {
Log.d("ThemeSystem", "加载自定义背景: $uriString")
val preventRefresh = getSharedPreferences("theme_prefs", Context.MODE_PRIVATE)
.getBoolean("prevent_background_refresh", false)
ThemeConfig.preventBackgroundRefresh = preventRefresh
if (!preventRefresh || ThemeConfig.customBackgroundUri?.toString() != newUri?.toString()) {
Log.d("ThemeSystem", "加载自定义背景: $uriString, 阻止刷新: $preventRefresh")
ThemeConfig.customBackgroundUri = newUri
ThemeConfig.backgroundImageLoaded = false
}

View File

@@ -299,7 +299,7 @@
<string name="flash_failed_message">フラッシュに失敗しました</string>
<!-- lkm/gki install -->
<string name="Lkm_install_methods">LKM の修復またはインストール</string>
<string name="GKI_install_methods">GKI のインストール</string>
<string name="GKI_install_methods">GKI/non-GKI のインストール</string>
<string name="kernel_version_log">カーネルのバージョン: %1$s</string>
<string name="tool_version_log">パッチ適用ツールの使用: %1$s</string>
<string name="configuration">設定</string>
@@ -324,4 +324,5 @@
<string name="susfs_disabled">SuSFS 無効</string>
<string name="background_set_success">背景の設定が成功しました</string>
<string name="background_removed">カスタム背景を削除しました</string>
<string name="root_require_for_install">root 権限が必要</string>
</resources>

View File

@@ -222,8 +222,8 @@
<string name="yes"></string>
<string name="no"></string>
<string name="failed_reboot">重启失败</string>
<string name="batch_authorization">批量授权</string>
<string name="batch_cancel_authorization">批量取消授权</string>
<string name="batch_authorization">授权</string>
<string name="batch_cancel_authorization">撤销</string>
<string name="color_yellow">黄色</string>
<string name="kpm">内核模块</string>
<string name="kpm_title">内核模块</string>
@@ -295,7 +295,7 @@
<string name="flash_failed_message">刷写失败</string>
<!-- lkm/gki install -->
<string name="Lkm_install_methods">LKM修补/安装</string>
<string name="GKI_install_methods">GKI安装</string>
<string name="GKI_install_methods">GKI/non-GKI安装</string>
<string name="kernel_version_log">内核版本:%1$s</string>
<string name="tool_version_log">使用修补工具:%1$s</string>
<string name="configuration">配置</string>
@@ -320,4 +320,5 @@
<string name="susfs_disabled">SuSFS 已禁用</string>
<string name="background_set_success">背景设置成功</string>
<string name="background_removed">已移除自定义背景</string>
<string name="root_require_for_install">需要 root 权限</string>
</resources>

View File

@@ -222,8 +222,8 @@
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="failed_reboot">Reboot Failed</string>
<string name="batch_authorization">Bulk license</string>
<string name="batch_cancel_authorization">Batch cancel authorization</string>
<string name="batch_authorization">authorizations</string>
<string name="batch_cancel_authorization">withdraw</string>
<string name="backup">Backup</string>
<string name="color_yellow">Yellow</string>
<string name="kpm">Kernel Module</string>
@@ -299,7 +299,7 @@
<string name="flash_failed_message">Flash failed</string>
<!-- lkm/gki install -->
<string name="Lkm_install_methods">LKM repair/installation</string>
<string name="GKI_install_methods">GKI installation</string>
<string name="GKI_install_methods">GKI/non-GKI installation</string>
<string name="kernel_version_log">Kernel version%1$s</string>
<string name="tool_version_log">Using the patching tool%1$s</string>
<string name="configuration">Configure</string>
@@ -324,4 +324,5 @@
<string name="susfs_disabled">SuSFS disabled</string>
<string name="background_set_success">Background set successfully</string>
<string name="background_removed">Removed custom backgrounds</string>
<string name="root_require_for_install">Requires root privileges</string>
</resources>