feat: 7种牌桌背景+7种卡面风格下拉选择,页面切换动画丝滑过渡
This commit is contained in:
parent
167ebdff27
commit
8f843a4e6f
@ -4,12 +4,15 @@ import android.os.Bundle
|
||||
import android.content.pm.ActivityInfo
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.navigation.NavBackStackEntry
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.compose.*
|
||||
import androidx.navigation.navArgument
|
||||
@ -191,10 +194,18 @@ fun UnoApp() {
|
||||
LocalCardTheme provides cardTheme,
|
||||
LocalTableBg provides tableBg
|
||||
) {
|
||||
val enterAnim: (AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition) = {
|
||||
fadeIn(animationSpec = tween(300)) + slideInHorizontally(animationSpec = tween(350)) { it / 4 }
|
||||
}
|
||||
val exitAnim: (AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition) = {
|
||||
fadeOut(animationSpec = tween(300)) + slideOutHorizontally(animationSpec = tween(350)) { -it / 4 }
|
||||
}
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = Screen.MainMenu.route,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
enterTransition = enterAnim,
|
||||
exitTransition = exitAnim
|
||||
) {
|
||||
composable(Screen.MainMenu.route) {
|
||||
MainMenuScreen(
|
||||
@ -416,15 +427,13 @@ fun UnoApp() {
|
||||
savedName = name
|
||||
prefs.edit().putString("player_name", name).apply()
|
||||
},
|
||||
onToggleTheme = {
|
||||
val next = CardTheme.values()[(cardTheme.ordinal + 1) % CardTheme.values().size]
|
||||
cardTheme = next
|
||||
CardTheme.save(context, next)
|
||||
onSetTheme = { theme ->
|
||||
cardTheme = theme
|
||||
CardTheme.save(context, theme)
|
||||
},
|
||||
onToggleBg = {
|
||||
val next = TableBg.values()[(tableBg.ordinal + 1) % TableBg.values().size]
|
||||
tableBg = next
|
||||
TableBg.save(context, next)
|
||||
onSetBg = { bg ->
|
||||
tableBg = bg
|
||||
TableBg.save(context, bg)
|
||||
},
|
||||
onToggleOrientation = {
|
||||
isLandscape = !isLandscape
|
||||
|
||||
@ -16,7 +16,6 @@ import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Popup
|
||||
@ -44,6 +43,10 @@ fun CardView(
|
||||
CardTheme.CLASSIC -> ClassicCard(card, cardBg, isWild, modifier, selected, playable, onClick, onLongPress = { showInfo = true })
|
||||
CardTheme.ELEGANT -> ElegantCard(card, cardBg, isWild, modifier, selected, playable, onClick, onLongPress = { showInfo = true })
|
||||
CardTheme.MIDNIGHT -> MidnightCard(card, cardBg, isWild, modifier, selected, playable, onClick, onLongPress = { showInfo = true })
|
||||
CardTheme.NEON -> NeonCard(card, cardBg, isWild, modifier, selected, playable, onClick, onLongPress = { showInfo = true })
|
||||
CardTheme.PASTEL -> PastelCard(card, cardBg, isWild, modifier, selected, playable, onClick, onLongPress = { showInfo = true })
|
||||
CardTheme.FOREST -> ForestCard(card, cardBg, isWild, modifier, selected, playable, onClick, onLongPress = { showInfo = true })
|
||||
CardTheme.OCEAN -> OceanCard(card, cardBg, isWild, modifier, selected, playable, onClick, onLongPress = { showInfo = true })
|
||||
}
|
||||
|
||||
if (showInfo) {
|
||||
@ -94,7 +97,6 @@ private fun ElegantCard(
|
||||
.then(Modifier.combinedClickable(onClick = onClick, onLongClick = onLongPress)),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
// Inner colored oval
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(0.82f).fillMaxHeight(0.78f)
|
||||
@ -105,14 +107,10 @@ private fun ElegantCard(
|
||||
),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = card.displayText,
|
||||
color = Color.White,
|
||||
Text(card.displayText, color = Color.White,
|
||||
fontSize = if (card.type == CardType.NUMBER && card.number >= 10) 16.sp else 22.sp,
|
||||
fontWeight = FontWeight.Black
|
||||
)
|
||||
fontWeight = FontWeight.Black)
|
||||
}
|
||||
// Corner numbers
|
||||
Text(card.displayText, modifier = Modifier.align(Alignment.TopStart).padding(6.dp, 4.dp),
|
||||
color = if (isWild) Color.White else cardBg, fontSize = 10.sp, fontWeight = FontWeight.Bold)
|
||||
Text(card.displayText, modifier = Modifier.align(Alignment.BottomEnd).padding(6.dp, 4.dp),
|
||||
@ -140,21 +138,137 @@ private fun MidnightCard(
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
|
||||
Text(
|
||||
text = card.displayText,
|
||||
color = if (isWild) Color.Magenta else getCardColor(card.color.name),
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Black
|
||||
)
|
||||
Text(card.displayText, color = if (isWild) Color.Magenta else getCardColor(card.color.name),
|
||||
fontSize = 24.sp, fontWeight = FontWeight.Black)
|
||||
if (card.color != CardColor.WILD) {
|
||||
// mini color dots
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(2.dp)) {
|
||||
repeat(3) {
|
||||
Box(Modifier.size(3.dp).clip(CircleShape).background(getCardColor(card.color.name)))
|
||||
repeat(3) { Box(Modifier.size(3.dp).clip(CircleShape).background(getCardColor(card.color.name))) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Neon ──
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun NeonCard(
|
||||
card: Card, cardBg: Color, isWild: Boolean,
|
||||
modifier: Modifier, selected: Boolean, playable: Boolean, onClick: () -> Unit, onLongPress: () -> Unit
|
||||
) {
|
||||
val neonColor = if (isWild) Color.Magenta else cardBg
|
||||
Box(
|
||||
modifier = modifier
|
||||
.width(60.dp).height(90.dp)
|
||||
.then(if (selected) Modifier.offset(y = (-10).dp) else Modifier)
|
||||
.shadow(if (selected) 10.dp else 4.dp, RoundedCornerShape(8.dp), ambientColor = neonColor, spotColor = neonColor)
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.background(Color(0xFF0A0A0A))
|
||||
.border(2.dp, neonColor, RoundedCornerShape(8.dp))
|
||||
.then(Modifier.combinedClickable(onClick = onClick, onLongClick = onLongPress)),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(card.displayText, color = neonColor, fontSize = 26.sp, fontWeight = FontWeight.Black)
|
||||
if (!isWild) {
|
||||
Text(card.displayText, modifier = Modifier.align(Alignment.TopStart).padding(6.dp, 4.dp),
|
||||
color = neonColor.copy(alpha = 0.6f), fontSize = 9.sp)
|
||||
Text(card.displayText, modifier = Modifier.align(Alignment.BottomEnd).padding(6.dp, 4.dp),
|
||||
color = neonColor.copy(alpha = 0.6f), fontSize = 9.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Pastel ──
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun PastelCard(
|
||||
card: Card, cardBg: Color, isWild: Boolean,
|
||||
modifier: Modifier, selected: Boolean, playable: Boolean, onClick: () -> Unit, onLongPress: () -> Unit
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.width(60.dp).height(90.dp)
|
||||
.then(if (selected) Modifier.offset(y = (-10).dp) else Modifier)
|
||||
.shadow(if (selected) 6.dp else 2.dp, RoundedCornerShape(16.dp))
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(
|
||||
if (isWild) Brush.horizontalGradient(listOf(UnoRed.copy(alpha = 0.15f), UnoBlue.copy(alpha = 0.15f),
|
||||
UnoGreen.copy(alpha = 0.15f), UnoYellow.copy(alpha = 0.15f)))
|
||||
else Brush.verticalGradient(listOf(Color.White, cardBg.copy(alpha = 0.08f)))
|
||||
)
|
||||
.border(1.5.dp, cardBg.copy(alpha = 0.3f), RoundedCornerShape(16.dp))
|
||||
.then(Modifier.combinedClickable(onClick = onClick, onLongClick = onLongPress)),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(card.displayText, color = cardBg, fontSize = 26.sp, fontWeight = FontWeight.Bold)
|
||||
if (isWild) {
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Row(Modifier.fillMaxWidth(0.6f), horizontalArrangement = Arrangement.SpaceEvenly) {
|
||||
listOf(UnoRed, UnoBlue, UnoGreen, UnoYellow).forEach { c ->
|
||||
Box(Modifier.size(5.dp).clip(CircleShape).background(c))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Forest ──
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun ForestCard(
|
||||
card: Card, cardBg: Color, isWild: Boolean,
|
||||
modifier: Modifier, selected: Boolean, playable: Boolean, onClick: () -> Unit, onLongPress: () -> Unit
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.width(60.dp).height(90.dp)
|
||||
.then(if (selected) Modifier.offset(y = (-10).dp) else Modifier)
|
||||
.shadow(if (selected) 6.dp else 2.dp, RoundedCornerShape(6.dp))
|
||||
.clip(RoundedCornerShape(6.dp))
|
||||
.background(
|
||||
if (isWild) Brush.verticalGradient(listOf(Color(0xFF2E7D32), Color(0xFF1B5E20)))
|
||||
else Brush.verticalGradient(listOf(Color(0xFFE8F5E9), Color(0xFFC8E6C9)))
|
||||
)
|
||||
.border(1.5.dp, if (isWild) Color(0xFF81C784) else Color(0xFF388E3C).copy(alpha = 0.3f), RoundedCornerShape(6.dp))
|
||||
.then(Modifier.combinedClickable(onClick = onClick, onLongClick = onLongPress)),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(card.displayText, color = if (isWild) Color.White else cardBg, fontSize = 24.sp, fontWeight = FontWeight.Black)
|
||||
}
|
||||
}
|
||||
|
||||
// ── Ocean ──
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun OceanCard(
|
||||
card: Card, cardBg: Color, isWild: Boolean,
|
||||
modifier: Modifier, selected: Boolean, playable: Boolean, onClick: () -> Unit, onLongPress: () -> Unit
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.width(60.dp).height(90.dp)
|
||||
.then(if (selected) Modifier.offset(y = (-10).dp) else Modifier)
|
||||
.shadow(if (selected) 6.dp else 3.dp, RoundedCornerShape(10.dp))
|
||||
.clip(RoundedCornerShape(10.dp))
|
||||
.background(
|
||||
if (isWild) Brush.verticalGradient(listOf(Color(0xFF0277BD), Color(0xFF00BCD4), Color(0xFF0288D1)))
|
||||
else Brush.verticalGradient(listOf(cardBg.copy(alpha = 0.7f), cardBg))
|
||||
)
|
||||
.border(1.dp, Color.White.copy(alpha = 0.3f), RoundedCornerShape(10.dp))
|
||||
.then(Modifier.combinedClickable(onClick = onClick, onLongClick = onLongPress)),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(card.displayText, color = Color.White, fontSize = 26.sp, fontWeight = FontWeight.Black)
|
||||
if (!isWild) {
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(3.dp)) {
|
||||
repeat(3) { Box(Modifier.size(4.dp).clip(CircleShape).background(Color.White.copy(alpha = 0.5f))) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,15 +323,12 @@ fun CardInfoPopup(card: Card, onDismiss: () -> Unit) {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Shared inner content for classic ──
|
||||
@Composable
|
||||
private fun CardContent(card: Card, isWild: Boolean) {
|
||||
if (isWild) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
|
||||
Text(
|
||||
text = if (card.type == CardType.WILD_DRAW_FOUR) "+4" else "W",
|
||||
color = Color.White, fontSize = 18.sp, fontWeight = FontWeight.Black
|
||||
)
|
||||
Text(if (card.type == CardType.WILD_DRAW_FOUR) "+4" else "W", color = Color.White,
|
||||
fontSize = 18.sp, fontWeight = FontWeight.Black)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Row(Modifier.fillMaxWidth(0.7f), horizontalArrangement = Arrangement.SpaceEvenly) {
|
||||
listOf(UnoRed, UnoBlue, UnoGreen, UnoYellow).forEach { c ->
|
||||
@ -267,12 +378,8 @@ fun CardBack(modifier: Modifier = Modifier, theme: CardTheme = LocalCardTheme.cu
|
||||
.border(2.dp, GoldAccent, RoundedCornerShape(14.dp)),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Box(
|
||||
Modifier.fillMaxWidth(0.75f).fillMaxHeight(0.7f)
|
||||
.clip(RoundedCornerShape(40))
|
||||
.background(DarkCard),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Box(Modifier.fillMaxWidth(0.75f).fillMaxHeight(0.7f).clip(RoundedCornerShape(40)).background(DarkCard),
|
||||
contentAlignment = Alignment.Center) {
|
||||
Text("UNO", color = GoldAccent, fontSize = 16.sp, fontWeight = FontWeight.Black)
|
||||
}
|
||||
}
|
||||
@ -285,9 +392,47 @@ fun CardBack(modifier: Modifier = Modifier, theme: CardTheme = LocalCardTheme.cu
|
||||
.background(DarkCard)
|
||||
.border(1.5.dp, Color.Magenta.copy(alpha = 0.5f), RoundedCornerShape(12.dp)),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text("U", color = Color.Magenta, fontSize = 32.sp, fontWeight = FontWeight.Black)
|
||||
) { Text("U", color = Color.Magenta, fontSize = 32.sp, fontWeight = FontWeight.Black) }
|
||||
}
|
||||
CardTheme.NEON -> {
|
||||
Box(
|
||||
modifier = modifier.width(60.dp).height(90.dp)
|
||||
.shadow(4.dp, RoundedCornerShape(8.dp), ambientColor = Color.Cyan)
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.background(Color(0xFF0A0A0A))
|
||||
.border(2.dp, Color.Cyan, RoundedCornerShape(8.dp)),
|
||||
contentAlignment = Alignment.Center
|
||||
) { Text("UNO", color = Color.Cyan, fontSize = 14.sp, fontWeight = FontWeight.Black) }
|
||||
}
|
||||
CardTheme.PASTEL -> {
|
||||
Box(
|
||||
modifier = modifier.width(60.dp).height(90.dp)
|
||||
.shadow(2.dp, RoundedCornerShape(16.dp))
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(Brush.verticalGradient(listOf(Color(0xFFFFF3E0), Color(0xFFFCE4EC))))
|
||||
.border(1.5.dp, Color(0xFFE0C0C0), RoundedCornerShape(16.dp)),
|
||||
contentAlignment = Alignment.Center
|
||||
) { Text("UNO", color = Color(0xFFCC9999), fontSize = 14.sp, fontWeight = FontWeight.Black) }
|
||||
}
|
||||
CardTheme.FOREST -> {
|
||||
Box(
|
||||
modifier = modifier.width(60.dp).height(90.dp)
|
||||
.shadow(2.dp, RoundedCornerShape(6.dp))
|
||||
.clip(RoundedCornerShape(6.dp))
|
||||
.background(Brush.verticalGradient(listOf(Color(0xFF2E7D32), Color(0xFF1B5E20))))
|
||||
.border(1.5.dp, Color(0xFF81C784), RoundedCornerShape(6.dp)),
|
||||
contentAlignment = Alignment.Center
|
||||
) { Text("UNO", color = Color.White, fontSize = 14.sp, fontWeight = FontWeight.Black) }
|
||||
}
|
||||
CardTheme.OCEAN -> {
|
||||
Box(
|
||||
modifier = modifier.width(60.dp).height(90.dp)
|
||||
.shadow(3.dp, RoundedCornerShape(10.dp))
|
||||
.clip(RoundedCornerShape(10.dp))
|
||||
.background(Brush.verticalGradient(listOf(Color(0xFF0277BD), Color(0xFF00BCD4))))
|
||||
.border(1.dp, Color.White.copy(alpha = 0.3f), RoundedCornerShape(10.dp)),
|
||||
contentAlignment = Alignment.Center
|
||||
) { Text("UNO", color = Color.White, fontSize = 14.sp, fontWeight = FontWeight.Black) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.unogame.ui.screens
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
@ -12,10 +13,15 @@ import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.unogame.model.CardColor
|
||||
import com.unogame.model.CardType
|
||||
import com.unogame.model.Card
|
||||
import com.unogame.ui.components.CardView
|
||||
import com.unogame.ui.theme.*
|
||||
|
||||
val HUMAN_NAME_PRESETS = listOf(
|
||||
@ -26,6 +32,8 @@ val HUMAN_NAME_PRESETS = listOf(
|
||||
"低带宽生物", "情感过载体"
|
||||
)
|
||||
|
||||
val SAMPLE_CARD = Card(CardColor.RED, CardType.NUMBER, 7)
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SettingsScreen(
|
||||
@ -34,13 +42,15 @@ fun SettingsScreen(
|
||||
currentBg: TableBg,
|
||||
isLandscape: Boolean,
|
||||
onNameChanged: (String) -> Unit,
|
||||
onToggleTheme: () -> Unit,
|
||||
onToggleBg: () -> Unit,
|
||||
onSetTheme: (CardTheme) -> Unit,
|
||||
onSetBg: (TableBg) -> Unit,
|
||||
onToggleOrientation: () -> Unit,
|
||||
onBack: () -> Unit
|
||||
) {
|
||||
var playerName by remember { mutableStateOf(initialName) }
|
||||
var showAbout by remember { mutableStateOf(false) }
|
||||
var themeExpanded by remember { mutableStateOf(false) }
|
||||
var bgExpanded by remember { mutableStateOf(false) }
|
||||
|
||||
Box(modifier = Modifier.fillMaxSize().background(LocalTableBg.current.color)) {
|
||||
Column(
|
||||
@ -120,21 +130,106 @@ fun SettingsScreen(
|
||||
|
||||
Spacer(modifier = Modifier.height(28.dp))
|
||||
|
||||
// Card theme
|
||||
// Appearance
|
||||
Text("外观设置", color = Color.White.copy(alpha = 0.6f), fontSize = 14.sp)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
SettingsRow(
|
||||
icon = Icons.Default.Palette,
|
||||
label = "卡面风格",
|
||||
|
||||
// Card theme dropdown
|
||||
ExposedDropdownMenuBox(
|
||||
expanded = themeExpanded,
|
||||
onExpandedChange = { themeExpanded = it }
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = currentTheme.displayName,
|
||||
onClick = onToggleTheme
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
label = { Text("卡面风格") },
|
||||
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = themeExpanded) },
|
||||
modifier = Modifier.fillMaxWidth().menuAnchor(),
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
focusedTextColor = Color.White,
|
||||
unfocusedTextColor = Color.White,
|
||||
focusedLabelColor = GoldAccent,
|
||||
unfocusedLabelColor = Color.White.copy(alpha = 0.6f),
|
||||
focusedBorderColor = GoldAccent,
|
||||
unfocusedBorderColor = Color.Gray,
|
||||
cursorColor = GoldAccent
|
||||
)
|
||||
SettingsRow(
|
||||
icon = Icons.Default.Wallpaper,
|
||||
label = "牌桌背景",
|
||||
)
|
||||
ExposedDropdownMenu(
|
||||
expanded = themeExpanded,
|
||||
onDismissRequest = { themeExpanded = false }
|
||||
) {
|
||||
CardTheme.values().forEach { theme ->
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
CompositionLocalProvider(LocalCardTheme provides theme) {
|
||||
CardView(card = SAMPLE_CARD, selected = false, playable = false, onClick = {},
|
||||
modifier = Modifier.size(30.dp, 45.dp))
|
||||
}
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Text(theme.displayName, fontSize = 14.sp)
|
||||
}
|
||||
},
|
||||
onClick = { onSetTheme(theme); themeExpanded = false }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
// Table bg dropdown
|
||||
ExposedDropdownMenuBox(
|
||||
expanded = bgExpanded,
|
||||
onExpandedChange = { bgExpanded = it }
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = currentBg.displayName,
|
||||
onClick = onToggleBg
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
label = { Text("牌桌背景") },
|
||||
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = bgExpanded) },
|
||||
modifier = Modifier.fillMaxWidth().menuAnchor(),
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
focusedTextColor = Color.White,
|
||||
unfocusedTextColor = Color.White,
|
||||
focusedLabelColor = GoldAccent,
|
||||
unfocusedLabelColor = Color.White.copy(alpha = 0.6f),
|
||||
focusedBorderColor = GoldAccent,
|
||||
unfocusedBorderColor = Color.Gray,
|
||||
cursorColor = GoldAccent
|
||||
)
|
||||
)
|
||||
ExposedDropdownMenu(
|
||||
expanded = bgExpanded,
|
||||
onDismissRequest = { bgExpanded = false }
|
||||
) {
|
||||
TableBg.values().forEach { bg ->
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(30.dp)
|
||||
.clip(RoundedCornerShape(6.dp))
|
||||
.border(1.dp, Color.White.copy(alpha = 0.2f), RoundedCornerShape(6.dp))
|
||||
.background(bg.color)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Text(bg.displayName, fontSize = 14.sp)
|
||||
}
|
||||
},
|
||||
onClick = { onSetBg(bg); bgExpanded = false }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
// Orientation
|
||||
SettingsRow(
|
||||
icon = if (isLandscape) Icons.Default.StayCurrentLandscape else Icons.Default.StayCurrentPortrait,
|
||||
label = "屏幕方向",
|
||||
|
||||
@ -5,7 +5,11 @@ import android.content.Context
|
||||
enum class CardTheme(val displayName: String) {
|
||||
CLASSIC("经典"),
|
||||
ELEGANT("优雅"),
|
||||
MIDNIGHT("暗夜");
|
||||
MIDNIGHT("暗夜"),
|
||||
NEON("霓虹"),
|
||||
PASTEL("马卡龙"),
|
||||
FOREST("森林"),
|
||||
OCEAN("海洋");
|
||||
|
||||
companion object {
|
||||
private const val KEY = "card_theme"
|
||||
|
||||
@ -6,7 +6,11 @@ import androidx.compose.ui.graphics.Color
|
||||
enum class TableBg(val displayName: String, val color: Color) {
|
||||
DARK("暗黑", Color(0xFF121212)),
|
||||
GREEN("墨绿", Color(0xFF1A3C2A)),
|
||||
BLUE("深蓝", Color(0xFF0D1B2A));
|
||||
BLUE("深蓝", Color(0xFF0D1B2A)),
|
||||
PURPLE("暗紫", Color(0xFF1A1035)),
|
||||
RED("酒红", Color(0xFF2D1111)),
|
||||
TEAL("深青", Color(0xFF0D2B2A)),
|
||||
CHARCOAL("炭灰", Color(0xFF1E1E1E));
|
||||
|
||||
companion object {
|
||||
private const val KEY = "table_bg"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user