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.*
import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha
import com.sukisu.ultra.ui.util.* import com.sukisu.ultra.ui.util.*
import androidx.core.content.edit
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
private inner class ThemeChangeContentObserver( private inner class ThemeChangeContentObserver(
@@ -45,7 +47,6 @@ class MainActivity : ComponentActivity() {
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
// Enable edge to edge // Enable edge to edge
enableEdgeToEdge() enableEdgeToEdge()
@@ -55,8 +56,18 @@ class MainActivity : ComponentActivity() {
super.onCreate(savedInstanceState) 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() loadThemeMode()
loadThemeColors() loadThemeColors()
loadDynamicColorState() loadDynamicColorState()
@@ -64,10 +75,12 @@ class MainActivity : ComponentActivity() {
val contentObserver = ThemeChangeContentObserver(Handler(mainLooper)) { val contentObserver = ThemeChangeContentObserver(Handler(mainLooper)) {
runOnUiThread { runOnUiThread {
if (!ThemeConfig.preventBackgroundRefresh) {
ThemeConfig.backgroundImageLoaded = false ThemeConfig.backgroundImageLoaded = false
loadCustomBackground() loadCustomBackground()
} }
} }
}
contentResolver.registerContentObserver( contentResolver.registerContentObserver(
android.provider.Settings.System.getUriFor("ui_night_mode"), 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>() private val destroyListeners = mutableListOf<() -> Unit>()
override fun onDestroy() { override fun onDestroy() {
@@ -141,7 +170,7 @@ private fun BottomBar(navController: NavHostController) {
containerColor = cardColor.copy(alpha = cardAlpha), containerColor = cardColor.copy(alpha = cardAlpha),
scrolledContainerColor = containerColor.copy(alpha = cardAlpha) scrolledContainerColor = containerColor.copy(alpha = cardAlpha)
).containerColor, ).containerColor,
tonalElevation = 0.dp tonalElevation = cardElevation
) { ) {
BottomBarDestination.entries.forEach { destination -> BottomBarDestination.entries.forEach { destination ->
if (destination == BottomBarDestination.Kpm) { if (destination == BottomBarDestination.Kpm) {
@@ -169,7 +198,6 @@ private fun BottomBar(navController: NavHostController) {
destination.iconNotSelected destination.iconNotSelected
}, },
contentDescription = stringResource(destination.label), contentDescription = stringResource(destination.label),
tint = if (isCurrentDestOnBackStack) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
) )
}, },
label = { label = {

View File

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

View File

@@ -1,7 +1,13 @@
package com.sukisu.ultra.ui.screen package com.sukisu.ultra.ui.screen
import android.annotation.SuppressLint
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.Crossfade 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.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.BoxWithConstraints 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.material.icons.filled.Security
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilterChip import androidx.compose.material3.FilterChip
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.ListItem import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarColors
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -44,7 +55,10 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier 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.geometry.Offset
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.pointerInput 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.AppProfileTemplateScreenDestination
import com.ramcosta.composedestinations.generated.destinations.TemplateEditorScreenDestination import com.ramcosta.composedestinations.generated.destinations.TemplateEditorScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
import com.sukisu.ultra.Natives import com.sukisu.ultra.Natives
import com.sukisu.ultra.R import com.sukisu.ultra.R
import com.sukisu.ultra.ui.component.SwitchItem import com.sukisu.ultra.ui.component.SwitchItem
import com.sukisu.ultra.ui.component.profile.AppProfileConfig import com.sukisu.ultra.ui.component.profile.AppProfileConfig
import com.sukisu.ultra.ui.component.profile.RootProfileConfig import com.sukisu.ultra.ui.component.profile.RootProfileConfig
import com.sukisu.ultra.ui.component.profile.TemplateConfig 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.LocalSnackbarHost
import com.sukisu.ultra.ui.util.forceStopApp import com.sukisu.ultra.ui.util.forceStopApp
import com.sukisu.ultra.ui.util.getSepolicy 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.util.setSepolicy
import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel
import com.sukisu.ultra.ui.viewmodel.getTemplateInfoById import com.sukisu.ultra.ui.viewmodel.getTemplateInfoById
import kotlinx.coroutines.launch
/** /**
* @author weishu * @author weishu
@@ -107,9 +122,18 @@ fun AppProfileScreen(
mutableStateOf(initialProfile) mutableStateOf(initialProfile)
} }
val cardColor = MaterialTheme.colorScheme.surfaceVariant
val cardAlpha = CardConfig.cardAlpha
Scaffold( Scaffold(
topBar = { topBar = {
TopBar( TopBar(
title = appInfo.label,
packageName = packageName,
colors = TopAppBarDefaults.topAppBarColors(
containerColor = cardColor.copy(alpha = cardAlpha),
scrolledContainerColor = cardColor.copy(alpha = cardAlpha)
),
onBack = dropUnlessResumed { navigator.popBackStack() }, onBack = dropUnlessResumed { navigator.popBackStack() },
scrollBehavior = scrollBehavior scrollBehavior = scrollBehavior
) )
@@ -181,22 +205,50 @@ private fun AppProfileInner(
val isRootGranted = profile.allowSu val isRootGranted = profile.allowSu
Column(modifier = modifier) { Column(modifier = modifier) {
ElevatedCard(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
shape = MaterialTheme.shapes.medium
) {
AppMenuBox(packageName) { AppMenuBox(packageName) {
ListItem( ListItem(
headlineContent = { Text(appLabel) }, headlineContent = {
supportingContent = { Text(packageName) }, Text(
text = appLabel,
style = MaterialTheme.typography.titleMedium
)
},
supportingContent = {
Text(
text = packageName,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
},
leadingContent = appIcon, leadingContent = appIcon,
) )
} }
}
ElevatedCard(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
shape = MaterialTheme.shapes.medium
) {
SwitchItem( SwitchItem(
icon = Icons.Filled.Security, icon = Icons.Filled.Security,
title = stringResource(id = R.string.superuser), title = stringResource(id = R.string.superuser),
checked = isRootGranted, checked = isRootGranted,
onCheckedChange = { onProfileChange(profile.copy(allowSu = it)) }, onCheckedChange = { onProfileChange(profile.copy(allowSu = it)) },
) )
}
Crossfade(targetState = isRootGranted, label = "") { current -> Crossfade(
targetState = isRootGranted,
label = "RootAccess"
) { current ->
Column( Column(
modifier = Modifier.padding(bottom = 6.dp + 48.dp + 6.dp /* SnackBar height */) modifier = Modifier.padding(bottom = 6.dp + 48.dp + 6.dp /* SnackBar height */)
) { ) {
@@ -211,6 +263,13 @@ private fun AppProfileInner(
var mode by rememberSaveable { var mode by rememberSaveable {
mutableStateOf(initialMode) mutableStateOf(initialMode)
} }
ElevatedCard(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
shape = MaterialTheme.shapes.medium
) {
ProfileBox(mode, true) { ProfileBox(mode, true) {
// template mode shouldn't change profile here! // template mode shouldn't change profile here!
if (it == Mode.Default || it == Mode.Custom) { if (it == Mode.Default || it == Mode.Custom) {
@@ -218,33 +277,73 @@ private fun AppProfileInner(
} }
mode = it 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( TemplateConfig(
profile = profile, profile = profile,
onViewTemplate = onViewTemplate, onViewTemplate = onViewTemplate,
onManageTemplate = onManageTemplate, onManageTemplate = onManageTemplate,
onProfileChange = onProfileChange onProfileChange = onProfileChange
) )
} else if (mode == Mode.Custom) { }
Mode.Custom -> {
RootProfileConfig( RootProfileConfig(
fixedName = true, fixedName = true,
profile = profile, profile = profile,
onProfileChange = onProfileChange onProfileChange = onProfileChange
) )
} }
else -> {}
}
}
}
}
} }
} else { } else {
val mode = if (profile.nonRootUseDefault) Mode.Default else Mode.Custom 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) { ProfileBox(mode, false) {
onProfileChange(profile.copy(nonRootUseDefault = (it == Mode.Default))) 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( AppProfileConfig(
fixedName = true, fixedName = true,
profile = profile, profile = profile,
enabled = modifyEnabled, enabled = mode == Mode.Custom,
onProfileChange = onProfileChange onProfileChange = onProfileChange
) )
} }
@@ -253,6 +352,8 @@ private fun AppProfileInner(
} }
} }
} }
}
}
private enum class Mode(@StringRes private val res: Int) { private enum class Mode(@StringRes private val res: Int) {
Default(R.string.profile_default), Template(R.string.profile_template), Custom(R.string.profile_custom); Default(R.string.profile_default), Template(R.string.profile_template), Custom(R.string.profile_custom);
@@ -264,20 +365,51 @@ private enum class Mode(@StringRes private val res: Int) {
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun TopBar( private fun TopBar(
title: String,
packageName: String,
onBack: () -> Unit, onBack: () -> Unit,
colors: TopAppBarColors,
scrollBehavior: TopAppBarScrollBehavior? = null scrollBehavior: TopAppBarScrollBehavior? = null
) { ) {
TopAppBar( TopAppBar(
title = { 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 = { navigationIcon = {
IconButton( IconButton(
onClick = onBack onClick = onBack,
) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) } 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), windowInsets = WindowInsets.safeDrawing.only(
scrollBehavior = scrollBehavior 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, hasTemplate: Boolean,
onModeChange: (Mode) -> Unit, onModeChange: (Mode) -> Unit,
) { ) {
Column(modifier = Modifier.padding(vertical = 8.dp)) {
ListItem( ListItem(
headlineContent = { Text(stringResource(R.string.profile)) }, headlineContent = {
supportingContent = { Text(mode.text) }, Text(
leadingContent = { Icon(Icons.Filled.AccountCircle, null) }, 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( Row(
modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally)
) { ) {
FilterChip( FilterChip(
selected = mode == Mode.Default, selected = mode == Mode.Default,
label = { Text(stringResource(R.string.profile_default)) },
onClick = { onModeChange(Mode.Default) }, onClick = { onModeChange(Mode.Default) },
label = {
Text(
text = stringResource(R.string.profile_default),
style = MaterialTheme.typography.bodyMedium
) )
},
shape = MaterialTheme.shapes.small
)
if (hasTemplate) { if (hasTemplate) {
FilterChip( FilterChip(
selected = mode == Mode.Template, selected = mode == Mode.Template,
label = { Text(stringResource(R.string.profile_template)) },
onClick = { onModeChange(Mode.Template) }, onClick = { onModeChange(Mode.Template) },
label = {
Text(
text = stringResource(R.string.profile_template),
style = MaterialTheme.typography.bodyMedium
)
},
shape = MaterialTheme.shapes.small
) )
} }
FilterChip( FilterChip(
selected = mode == Mode.Custom, selected = mode == Mode.Custom,
label = { Text(stringResource(R.string.profile_custom)) },
onClick = { onModeChange(Mode.Custom) }, onClick = { onModeChange(Mode.Custom) },
label = {
Text(
text = stringResource(R.string.profile_custom),
style = MaterialTheme.typography.bodyMedium
)
},
shape = MaterialTheme.shapes.small
)
}
}
) )
} }
})
} }
@SuppressLint("UnusedBoxWithConstraintsScope")
@Composable @Composable
private fun AppMenuBox(packageName: String, content: @Composable () -> Unit) { private fun AppMenuBox(packageName: String, content: @Composable () -> Unit) {
var expanded by remember { mutableStateOf(false) } var expanded by remember { mutableStateOf(false) }
var touchPoint: Offset by remember { mutableStateOf(Offset.Zero) } var touchPoint: Offset by remember { mutableStateOf(Offset.Zero) }
val density = LocalDensity.current val density = LocalDensity.current
@@ -329,13 +509,14 @@ private fun AppMenuBox(packageName: String, content: @Composable () -> Unit) {
Modifier Modifier
.fillMaxSize() .fillMaxSize()
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures { detectTapGestures(
onLongPress = {
touchPoint = it touchPoint = it
expanded = true expanded = true
} }
)
} }
) { ) {
content() content()
val (offsetX, offsetY) = with(density) { val (offsetX, offsetY) = with(density) {
@@ -349,43 +530,64 @@ private fun AppMenuBox(packageName: String, content: @Composable () -> Unit) {
expanded = false expanded = false
}, },
) { ) {
DropdownMenuItem( AppMenuOption(
text = { Text(stringResource(id = R.string.launch_app)) }, text = stringResource(id = R.string.launch_app),
onClick = { onClick = {
expanded = false expanded = false
launchApp(packageName) launchApp(packageName)
}, }
) )
DropdownMenuItem(
text = { Text(stringResource(id = R.string.force_stop_app)) }, AppMenuOption(
text = stringResource(id = R.string.force_stop_app),
onClick = { onClick = {
expanded = false expanded = false
forceStopApp(packageName) forceStopApp(packageName)
}, }
) )
DropdownMenuItem(
text = { Text(stringResource(id = R.string.restart_app)) }, AppMenuOption(
text = stringResource(id = R.string.restart_app),
onClick = { onClick = {
expanded = false expanded = false
restartApp(packageName) restartApp(packageName)
}, }
) )
} }
} }
} }
@Composable
private fun AppMenuOption(text: String, onClick: () -> Unit) {
DropdownMenuItem(
text = {
Text(
text = text,
style = MaterialTheme.typography.bodyMedium
)
},
onClick = onClick
)
}
@Preview @Preview
@Composable @Composable
private fun AppProfilePreview() { private fun AppProfilePreview() {
var profile by remember { mutableStateOf(Natives.Profile("")) } var profile by remember { mutableStateOf(Natives.Profile("")) }
Surface {
AppProfileInner( AppProfileInner(
packageName = "icu.nullptr.test", packageName = "icu.nullptr.test",
appLabel = "Test", appLabel = "Test",
appIcon = { Icon(Icons.Filled.Android, null) }, appIcon = {
Icon(
imageVector = Icons.Filled.Android,
contentDescription = null,
)
},
profile = profile, profile = profile,
onProfileChange = { onProfileChange = {
profile = it 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.Android
import androidx.compose.material.icons.filled.Archive import androidx.compose.material.icons.filled.Archive
import androidx.compose.material.icons.filled.Code 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.Info
import androidx.compose.material.icons.filled.Memory import androidx.compose.material.icons.filled.Memory
import androidx.compose.material.icons.filled.PhoneAndroid import androidx.compose.material.icons.filled.PhoneAndroid
import androidx.compose.material.icons.filled.Refresh 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.Security
import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.filled.Storage 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.ksuApp
import com.sukisu.ultra.ui.component.rememberConfirmDialog import com.sukisu.ultra.ui.component.rememberConfirmDialog
import com.sukisu.ultra.ui.theme.CardConfig 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.theme.getCardColors
import com.sukisu.ultra.ui.util.checkNewVersion import com.sukisu.ultra.ui.util.checkNewVersion
import com.sukisu.ultra.ui.util.getKpmModuleCount import com.sukisu.ultra.ui.util.getKpmModuleCount
@@ -245,11 +244,11 @@ fun HomeScreen(navigator: DestinationsNavigator) {
) { ) {
ElevatedCard( ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.secondaryContainer), colors = getCardColors(MaterialTheme.colorScheme.secondaryContainer),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp), elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier modifier = Modifier
.clip(MaterialTheme.shapes.medium) .clip(MaterialTheme.shapes.medium)
.shadow( .shadow(
elevation = 0.dp, elevation = cardElevation,
shape = MaterialTheme.shapes.medium, shape = MaterialTheme.shapes.medium,
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f) spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)
) )
@@ -267,7 +266,6 @@ fun HomeScreen(navigator: DestinationsNavigator) {
Icon( Icon(
imageVector = Icons.Outlined.Info, imageVector = Icons.Outlined.Info,
contentDescription = null, contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(end = 12.dp) modifier = Modifier.padding(end = 12.dp)
) )
Text( Text(
@@ -365,7 +363,6 @@ fun RebootDropdownItem(@StringRes id: Int, reason: String = "") {
Icon( Icon(
imageVector = Icons.Filled.Refresh, imageVector = Icons.Filled.Refresh,
contentDescription = null, contentDescription = null,
tint = MaterialTheme.colorScheme.primary
) )
} }
) )
@@ -393,12 +390,11 @@ private fun TopBar(
scrolledContainerColor = cardColor.copy(alpha = cardAlpha) scrolledContainerColor = cardColor.copy(alpha = cardAlpha)
), ),
actions = { actions = {
if (kernelVersion.isGKI()) { if (rootAvailable() || kernelVersion.isGKI()) {
IconButton(onClick = onInstallClick) { IconButton(onClick = onInstallClick) {
Icon( Icon(
Icons.Filled.Archive, Icons.Filled.Archive,
contentDescription = stringResource(R.string.install), contentDescription = stringResource(R.string.install),
tint = MaterialTheme.colorScheme.primary
) )
} }
} }
@@ -409,7 +405,6 @@ private fun TopBar(
Icon( Icon(
Icons.Filled.Refresh, Icons.Filled.Refresh,
contentDescription = stringResource(R.string.reboot), contentDescription = stringResource(R.string.reboot),
tint = MaterialTheme.colorScheme.primary
) )
DropdownMenu( DropdownMenu(
@@ -444,22 +439,22 @@ private fun StatusCard(
onClickInstall: () -> Unit = {} onClickInstall: () -> Unit = {}
) { ) {
ElevatedCard( ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHigh), colors = getCardColors(MaterialTheme.colorScheme.surfaceVariant),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp), elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(MaterialTheme.shapes.large) .clip(MaterialTheme.shapes.large)
.shadow( .shadow(
elevation = 0.dp, elevation = cardElevation,
shape = MaterialTheme.shapes.large, shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f) spotColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.1f)
) )
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clickable(enabled = kernelVersion.isGKI()) { .clickable {
if (kernelVersion.isGKI()) { if (rootAvailable() || kernelVersion.isGKI()) {
onClickInstall() onClickInstall()
} }
} }
@@ -620,12 +615,12 @@ fun WarningCard(
) { ) {
ElevatedCard( ElevatedCard(
colors = getCardColors(color), colors = getCardColors(color),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp), elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(MaterialTheme.shapes.large) .clip(MaterialTheme.shapes.large)
.shadow( .shadow(
elevation = 0.dp, elevation = cardElevation,
shape = MaterialTheme.shapes.large, shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.error.copy(alpha = 0.1f) 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") val links = listOf("https://github.com/zako", "https://github.com/udochina")
ElevatedCard( ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.tertiaryContainer), colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHigh),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp), elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.wrapContentHeight() .wrapContentHeight()
.clip(MaterialTheme.shapes.large) .clip(MaterialTheme.shapes.large)
.shadow( .shadow(
elevation = 0.dp, elevation = cardElevation,
shape = MaterialTheme.shapes.large, shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.tertiary.copy(alpha = 0.1f) spotColor = MaterialTheme.colorScheme.tertiary.copy(alpha = 0.1f)
) )
@@ -682,27 +677,18 @@ fun ContributionCard() {
.padding(24.dp), .padding(24.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Icon(
imageVector = Icons.Filled.Code,
contentDescription = null,
tint = MaterialTheme.colorScheme.onTertiaryContainer,
modifier = Modifier
.padding(end = 16.dp)
.size(24.dp)
)
Column { Column {
Text( Text(
text = stringResource(R.string.home_ContributionCard_kernelsu), text = stringResource(R.string.home_ContributionCard_kernelsu),
style = MaterialTheme.typography.titleSmall, style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.onTertiaryContainer color = MaterialTheme.colorScheme.onSurfaceVariant
) )
Spacer(Modifier.height(4.dp)) Spacer(Modifier.height(4.dp))
Text( Text(
text = stringResource(R.string.home_click_to_ContributionCard_kernelsu), text = stringResource(R.string.home_click_to_ContributionCard_kernelsu),
style = MaterialTheme.typography.bodyMedium, 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) val url = stringResource(R.string.home_learn_kernelsu_url)
ElevatedCard( ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.primaryContainer), colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHigh),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp), elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(MaterialTheme.shapes.large) .clip(MaterialTheme.shapes.large)
.shadow( .shadow(
elevation = 0.dp, elevation = cardElevation,
shape = MaterialTheme.shapes.large, shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f) spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)
) )
@@ -735,27 +721,18 @@ fun LearnMoreCard() {
.padding(24.dp), .padding(24.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Icon(
imageVector = Icons.Filled.School,
contentDescription = null,
tint = MaterialTheme.colorScheme.onPrimaryContainer,
modifier = Modifier
.padding(end = 16.dp)
.size(24.dp)
)
Column { Column {
Text( Text(
text = stringResource(R.string.home_learn_kernelsu), text = stringResource(R.string.home_learn_kernelsu),
style = MaterialTheme.typography.titleSmall, style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.onPrimaryContainer color = MaterialTheme.colorScheme.onSurfaceVariant
) )
Spacer(Modifier.height(4.dp)) Spacer(Modifier.height(4.dp))
Text( Text(
text = stringResource(R.string.home_click_to_learn_kernelsu), text = stringResource(R.string.home_click_to_learn_kernelsu),
style = MaterialTheme.typography.bodyMedium, 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 val uriHandler = LocalUriHandler.current
ElevatedCard( ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.secondaryContainer), colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHigh),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp), elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(MaterialTheme.shapes.large) .clip(MaterialTheme.shapes.large)
.shadow( .shadow(
elevation = 0.dp, elevation = cardElevation,
shape = MaterialTheme.shapes.large, shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.secondary.copy(alpha = 0.1f) spotColor = MaterialTheme.colorScheme.secondary.copy(alpha = 0.1f)
) )
@@ -787,27 +764,18 @@ fun DonateCard() {
.padding(24.dp), .padding(24.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Icon(
imageVector = Icons.Filled.Favorite,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSecondaryContainer,
modifier = Modifier
.padding(end = 16.dp)
.size(24.dp)
)
Column { Column {
Text( Text(
text = stringResource(R.string.home_support_title), text = stringResource(R.string.home_support_title),
style = MaterialTheme.typography.titleSmall, style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.onSecondaryContainer color = MaterialTheme.colorScheme.onSurfaceVariant
) )
Spacer(Modifier.height(4.dp)) Spacer(Modifier.height(4.dp))
Text( Text(
text = stringResource(R.string.home_support_content), text = stringResource(R.string.home_support_content),
style = MaterialTheme.typography.bodyMedium, 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( ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHighest), colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHighest),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp), elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(MaterialTheme.shapes.large) .clip(MaterialTheme.shapes.large)
.shadow( .shadow(
elevation = 0.dp, elevation = cardElevation,
shape = MaterialTheme.shapes.large, shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.05f) spotColor = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.05f)
) )
@@ -858,7 +826,7 @@ private fun InfoCard() {
imageVector = icon, imageVector = icon,
contentDescription = label, contentDescription = label,
modifier = Modifier.size(24.dp), modifier = Modifier.size(24.dp),
tint = MaterialTheme.colorScheme.primary tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f),
) )
Spacer(modifier = Modifier.width(16.dp)) Spacer(modifier = Modifier.width(16.dp))
Column( Column(

View File

@@ -15,7 +15,14 @@ import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.LocalIndication import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource 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.rememberScrollState
import androidx.compose.foundation.selection.toggleable import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.verticalScroll 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.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.AutoFixHigh import androidx.compose.material.icons.filled.AutoFixHigh
import androidx.compose.material.icons.filled.FileUpload import androidx.compose.material.icons.filled.FileUpload
import androidx.compose.material3.* import androidx.compose.material3.AlertDialog
import androidx.compose.runtime.* 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.Alignment
import androidx.compose.ui.Modifier 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.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.Role
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp 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.ListOption
import com.maxkeppeler.sheets.list.models.ListSelection
import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import com.sukisu.ultra.R 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.DialogHandle
import com.sukisu.ultra.ui.component.SlotSelectionDialog import com.sukisu.ultra.ui.component.SlotSelectionDialog
import com.sukisu.ultra.ui.component.rememberConfirmDialog import com.sukisu.ultra.ui.component.rememberConfirmDialog
import com.sukisu.ultra.ui.component.rememberCustomDialog import com.sukisu.ultra.ui.component.rememberCustomDialog
import com.sukisu.ultra.flash.HorizonKernelFlashProgress import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha
import com.sukisu.ultra.flash.HorizonKernelState import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
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.getCardColors 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 * @author weishu
@@ -69,6 +113,8 @@ fun InstallScreen(navigator: DestinationsNavigator) {
val horizonKernelState = remember { HorizonKernelState() } val horizonKernelState = remember { HorizonKernelState() }
val flashState by horizonKernelState.state.collectAsState() val flashState by horizonKernelState.state.collectAsState()
val summary = stringResource(R.string.horizon_kernel_summary) val summary = stringResource(R.string.horizon_kernel_summary)
val kernelVersion = getKernelVersion()
val isGKI = kernelVersion.isGKI()
val onFlashComplete = { val onFlashComplete = {
showRebootDialog = true showRebootDialog = true
@@ -133,7 +179,6 @@ fun InstallScreen(navigator: DestinationsNavigator) {
summary = summary summary = summary
) )
installMethod = horizonMethod installMethod = horizonMethod
onInstall()
} }
) )
@@ -149,7 +194,7 @@ fun InstallScreen(navigator: DestinationsNavigator) {
} }
val onClickNext = { val onClickNext = {
if (lkmSelection == LkmSelection.KmiNone && currentKmi.isBlank()) { if (isGKI && lkmSelection == LkmSelection.KmiNone && currentKmi.isBlank()) {
selectKmiDialog.show() selectKmiDialog.show()
} else { } else {
onInstall() onInstall()
@@ -191,8 +236,10 @@ fun InstallScreen(navigator: DestinationsNavigator) {
.padding(innerPadding) .padding(innerPadding)
.nestedScroll(scrollBehavior.nestedScrollConnection) .nestedScroll(scrollBehavior.nestedScrollConnection)
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
.padding(top = 12.dp)
) { ) {
SelectInstallMethod( SelectInstallMethod(
isGKI = isGKI,
onSelected = { method -> onSelected = { method ->
if (method is InstallMethod.HorizonKernel && method.uri != null && method.slot == null) { if (method is InstallMethod.HorizonKernel && method.uri != null && method.slot == null) {
tempKernelUri = method.uri tempKernelUri = method.uri
@@ -218,32 +265,73 @@ fun InstallScreen(navigator: DestinationsNavigator) {
.padding(16.dp) .padding(16.dp)
) { ) {
(lkmSelection as? LkmSelection.LkmUri)?.let { (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( Text(
stringResource( text = stringResource(
id = R.string.selected_lkm, id = R.string.selected_lkm,
it.uri.lastPathSegment ?: "(file)" it.uri.lastPathSegment ?: "(file)"
) ),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(16.dp)
) )
} }
}
(installMethod as? InstallMethod.HorizonKernel)?.let { method -> (installMethod as? InstallMethod.HorizonKernel)?.let { method ->
if (method.slot != null) { 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( Text(
stringResource( text = stringResource(
id = R.string.selected_slot, id = R.string.selected_slot,
if (method.slot == "a") stringResource(id = R.string.slot_a) if (method.slot == "a") stringResource(id = R.string.slot_a)
else stringResource(id = R.string.slot_b) else stringResource(id = R.string.slot_b)
) ),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(16.dp)
) )
} }
} }
}
Button( Button(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
enabled = installMethod != null && !flashState.isFlashing, 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( Text(
stringResource(id = R.string.install_next), stringResource(id = R.string.install_next),
fontSize = MaterialTheme.typography.bodyMedium.fontSize style = MaterialTheme.typography.bodyMedium
) )
} }
} }
@@ -305,7 +393,10 @@ sealed class InstallMethod {
} }
@Composable @Composable
private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) { private fun SelectInstallMethod(
isGKI: Boolean = false,
onSelected: (InstallMethod) -> Unit = {}
) {
val rootAvailable = rootAvailable() val rootAvailable = rootAvailable()
val isAbDevice = isAbDevice() val isAbDevice = isAbDevice()
val horizonKernelSummary = stringResource(R.string.horizon_kernel_summary) 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 LKMExpanded by remember { mutableStateOf(false) }
var GKIExpanded 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( ListItem(
leadingContent = { Icon(Icons.Filled.AutoFixHigh, null) }, leadingContent = {
headlineContent = { Text(stringResource(R.string.Lkm_install_methods)) }, 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 { modifier = Modifier.clickable {
LKMExpanded = !LKMExpanded LKMExpanded = !LKMExpanded
} }
) )
radioOptions.take(3).forEach { option ->
AnimatedVisibility( AnimatedVisibility(
visible = LKMExpanded, 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() } 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( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
@@ -419,51 +557,102 @@ private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
indication = LocalIndication.current, indication = LocalIndication.current,
interactionSource = interactionSource interactionSource = interactionSource
) )
.padding(vertical = 8.dp, horizontal = 12.dp)
) { ) {
RadioButton( RadioButton(
selected = option.javaClass == selectedOption?.javaClass, selected = option.javaClass == selectedOption?.javaClass,
onClick = { onClick(option) }, onClick = null,
interactionSource = interactionSource interactionSource = interactionSource,
colors = RadioButtonDefaults.colors(
selectedColor = MaterialTheme.colorScheme.primary,
unselectedColor = MaterialTheme.colorScheme.onSurfaceVariant
)
) )
Column( Column(
modifier = Modifier.padding(vertical = 12.dp) modifier = Modifier
.padding(start = 10.dp)
.weight(1f)
) { ) {
Text( Text(
text = stringResource(id = option.label), text = stringResource(id = option.label),
fontSize = MaterialTheme.typography.titleMedium.fontSize, style = MaterialTheme.typography.bodyLarge
fontFamily = MaterialTheme.typography.titleMedium.fontFamily,
fontStyle = MaterialTheme.typography.titleMedium.fontStyle
) )
option.summary?.let { option.summary?.let {
Text( Text(
text = it, text = it,
fontSize = MaterialTheme.typography.bodySmall.fontSize, style = MaterialTheme.typography.bodySmall,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily, color = MaterialTheme.colorScheme.onSurfaceVariant
fontStyle = MaterialTheme.typography.bodySmall.fontStyle
) )
} }
} }
} }
} }
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( ListItem(
leadingContent = { Icon(Icons.Filled.FileUpload, null) }, leadingContent = {
headlineContent = { Text(stringResource(R.string.GKI_install_methods)) }, 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 { modifier = Modifier.clickable {
GKIExpanded = !GKIExpanded GKIExpanded = !GKIExpanded
} }
) )
AnimatedVisibility( AnimatedVisibility(
visible = GKIExpanded, 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 -> radioOptions.drop(3).forEach { option ->
val interactionSource = remember { MutableInteractionSource() } 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( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
@@ -475,32 +664,76 @@ private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) {
indication = LocalIndication.current, indication = LocalIndication.current,
interactionSource = interactionSource interactionSource = interactionSource
) )
.padding(vertical = 8.dp, horizontal = 12.dp)
) { ) {
RadioButton( RadioButton(
selected = option.javaClass == selectedOption?.javaClass, selected = option.javaClass == selectedOption?.javaClass,
onClick = { onClick(option) }, onClick = null,
interactionSource = interactionSource interactionSource = interactionSource,
colors = RadioButtonDefaults.colors(
selectedColor = MaterialTheme.colorScheme.primary,
unselectedColor = MaterialTheme.colorScheme.onSurfaceVariant
)
) )
Column( Column(
modifier = Modifier.padding(vertical = 12.dp) modifier = Modifier
.padding(start = 10.dp)
.weight(1f)
) { ) {
Text( Text(
text = stringResource(id = option.label), text = stringResource(id = option.label),
fontSize = MaterialTheme.typography.titleMedium.fontSize, style = MaterialTheme.typography.bodyLarge
fontFamily = MaterialTheme.typography.titleMedium.fontFamily,
fontStyle = MaterialTheme.typography.titleMedium.fontStyle
) )
option.summary?.let { option.summary?.let {
Text( Text(
text = it, text = it,
fontSize = MaterialTheme.typography.bodySmall.fontSize, style = MaterialTheme.typography.bodySmall,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily, color = MaterialTheme.colorScheme.onSurfaceVariant
fontStyle = MaterialTheme.typography.bodySmall.fontStyle
) )
} }
} }
} }
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>()) { val supportedKmi by produceState(initialValue = emptyList<String>()) {
value = getSupportedKmis() value = getSupportedKmis()
} }
val listOptions = supportedKmi.map { value -> val options = supportedKmi.map { value ->
ListOption( ListOption(
titleText = value, titleText = value
subtitleText = null,
icon = null
) )
} }
var selection: String? = null var selection by remember { mutableStateOf<String?>(null) }
val cardColor = if (!ThemeConfig.useDynamicColor) { val backgroundColor = MaterialTheme.colorScheme.surfaceContainerHighest
ThemeConfig.currentTheme.ButtonContrast
} else {
MaterialTheme.colorScheme.secondaryContainer
}
AlertDialog( MaterialTheme(
onDismissRequest = { colorScheme = MaterialTheme.colorScheme.copy(
dismiss() surface = backgroundColor
}, )
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)
) { ) {
Column { ListDialog(state = rememberUseCaseState(visible = true, onFinishedRequest = {
Text(text = option.titleText)
option.subtitleText?.let {
Text(
text = it,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
}
}
},
confirmButton = {
TextButton(
onClick = {
if (selection != null) {
onSelected(selection) onSelected(selection)
} }, onCloseRequest = {
dismiss() 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 = {}, onLkmUpload: () -> Unit = {},
scrollBehavior: TopAppBarScrollBehavior? = null scrollBehavior: TopAppBarScrollBehavior? = null
) { ) {
val cardColor = MaterialTheme.colorScheme.secondaryContainer val cardColor = MaterialTheme.colorScheme.surfaceVariant
val cardAlpha = CardConfig.cardAlpha val cardAlpha = cardAlpha
TopAppBar( TopAppBar(
title = { Text(stringResource(R.string.install)) }, title = {
Text(
stringResource(R.string.install),
style = MaterialTheme.typography.titleLarge
)
},
colors = TopAppBarDefaults.topAppBarColors( colors = TopAppBarDefaults.topAppBarColors(
containerColor = cardColor.copy(alpha = cardAlpha), containerColor = cardColor.copy(alpha = cardAlpha),
scrolledContainerColor = cardColor.copy(alpha = cardAlpha) scrolledContainerColor = cardColor.copy(alpha = cardAlpha)
), ),
navigationIcon = { navigationIcon = {
IconButton(onClick = onBack) { IconButton(onClick = onBack) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = stringResource(R.string.back)
)
} }
}, },
windowInsets = WindowInsets.safeDrawing.only( windowInsets = WindowInsets.safeDrawing.only(

View File

@@ -38,6 +38,7 @@ import java.io.FileInputStream
import java.io.InputStreamReader import java.io.InputStreamReader
import java.net.* import java.net.*
import android.app.Activity import android.app.Activity
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
/** /**
* KPM 管理界面 * KPM 管理界面
@@ -290,7 +291,6 @@ fun KpmScreen(
Icon( Icon(
imageVector = Icons.Filled.Refresh, imageVector = Icons.Filled.Refresh,
contentDescription = stringResource(R.string.refresh), contentDescription = stringResource(R.string.refresh),
tint = MaterialTheme.colorScheme.primary
) )
} }
} }
@@ -309,7 +309,6 @@ fun KpmScreen(
Icon( Icon(
imageVector = Icons.Filled.Add, imageVector = Icons.Filled.Add,
contentDescription = stringResource(R.string.kpm_install), contentDescription = stringResource(R.string.kpm_install),
tint = MaterialTheme.colorScheme.onPrimaryContainer
) )
}, },
text = { text = {
@@ -346,7 +345,6 @@ fun KpmScreen(
Icon( Icon(
imageVector = Icons.Filled.Info, imageVector = Icons.Filled.Info,
contentDescription = null, contentDescription = null,
tint = MaterialTheme.colorScheme.onSecondaryContainer,
modifier = Modifier modifier = Modifier
.padding(end = 16.dp) .padding(end = 16.dp)
.size(24.dp) .size(24.dp)
@@ -654,12 +652,12 @@ private fun KpmModuleItem(
Card( Card(
colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHigh), colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHigh),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp), elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(MaterialTheme.shapes.large) .clip(MaterialTheme.shapes.large)
.shadow( .shadow(
elevation = 0.dp, elevation = cardElevation,
shape = MaterialTheme.shapes.large, shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f) 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 androidx.core.net.toUri
import com.sukisu.ultra.ui.theme.ThemeConfig import com.sukisu.ultra.ui.theme.ThemeConfig
import com.sukisu.ultra.R import com.sukisu.ultra.R
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@@ -233,7 +234,6 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
Icon( Icon(
imageVector = Icons.Filled.MoreVert, imageVector = Icons.Filled.MoreVert,
contentDescription = stringResource(id = R.string.settings), contentDescription = stringResource(id = R.string.settings),
tint = MaterialTheme.colorScheme.primary
) )
DropdownMenu( DropdownMenu(
@@ -294,7 +294,6 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
Icon( Icon(
imageVector = Icons.Outlined.Download, imageVector = Icons.Outlined.Download,
contentDescription = stringResource(R.string.backup), contentDescription = stringResource(R.string.backup),
tint = MaterialTheme.colorScheme.primary
) )
}, },
onClick = { onClick = {
@@ -308,7 +307,6 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
Icon( Icon(
imageVector = Icons.Outlined.Refresh, imageVector = Icons.Outlined.Refresh,
contentDescription = stringResource(R.string.restore), contentDescription = stringResource(R.string.restore),
tint = MaterialTheme.colorScheme.primary
) )
}, },
onClick = { onClick = {
@@ -343,7 +341,6 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
Icon( Icon(
imageVector = Icons.Filled.Add, imageVector = Icons.Filled.Add,
contentDescription = moduleInstall, contentDescription = moduleInstall,
tint = MaterialTheme.colorScheme.onPrimaryContainer
) )
}, },
text = { text = {
@@ -690,12 +687,12 @@ fun ModuleItem(
) { ) {
ElevatedCard( ElevatedCard(
colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHigh), colors = getCardColors(MaterialTheme.colorScheme.surfaceContainerHigh),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp), elevation = CardDefaults.cardElevation(defaultElevation = cardElevation),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(MaterialTheme.shapes.large) .clip(MaterialTheme.shapes.large)
.shadow( .shadow(
elevation = 0.dp, elevation = cardElevation,
shape = MaterialTheme.shapes.large, shape = MaterialTheme.shapes.large,
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f) spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f)
) )
@@ -919,7 +916,6 @@ fun ModuleItem(
modifier = Modifier.size(20.dp), modifier = Modifier.size(20.dp),
imageVector = Icons.Outlined.Delete, imageVector = Icons.Outlined.Delete,
contentDescription = null, contentDescription = null,
tint = MaterialTheme.colorScheme.onErrorContainer
) )
} else { } else {
Icon( Icon(

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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