manager: continue to improve the UI
- Expose anykernel3 flashing as long as there is root. - Opt some styles
This commit is contained in:
@@ -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 = {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -252,6 +351,8 @@ private fun AppProfileInner(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum class Mode(@StringRes private val res: Int) {
|
private enum class Mode(@StringRes private val res: Int) {
|
||||||
@@ -264,20 +365,51 @@ private enum class Mode(@StringRes private val res: Int) {
|
|||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@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
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user