feat: 出牌记录弹窗重构,上下箭头外置、宽度拉满、纯文字区域扩高;状态条扩展至2行
This commit is contained in:
parent
13a1e9432a
commit
cdfcce357d
@ -65,8 +65,8 @@ fun GameScreen(
|
||||
.verticalScroll(scrollState)
|
||||
.padding(top = 24.dp, bottom = 100.dp)
|
||||
) {
|
||||
// Game message - fixed height area
|
||||
Box(modifier = Modifier.fillMaxWidth().heightIn(min = 36.dp)) {
|
||||
// 出牌状态条,最多2行
|
||||
Box(modifier = Modifier.fillMaxWidth().heightIn(min = 36.dp, max = 56.dp)) {
|
||||
if (gameState.message.isNotEmpty()) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
@ -83,8 +83,10 @@ fun GameScreen(
|
||||
Text(
|
||||
text = gameState.message,
|
||||
color = GoldAccent,
|
||||
fontSize = 14.sp,
|
||||
fontSize = 13.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
maxLines = 2,
|
||||
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Icon(
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
package com.unogame.ui.screens
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
@ -12,6 +17,8 @@ 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.draw.scale
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
@ -371,91 +378,129 @@ fun LocalGameScreen(
|
||||
val creamBg = Color(0xFFFFF8E1) // 护眼米白
|
||||
val dimText = Color(0xFF555555) // 浅色底上的暗灰文字
|
||||
|
||||
// 关闭
|
||||
// 列表状态放在外层供标题栏和内容区共享
|
||||
val listState = rememberLazyListState()
|
||||
val canScrollForward by remember { derivedStateOf { listState.canScrollForward } }
|
||||
val canScrollBackward by remember { derivedStateOf { listState.canScrollBackward } }
|
||||
|
||||
AlertDialog(
|
||||
modifier = Modifier.fillMaxWidth(0.98f),
|
||||
onDismissRequest = { showLogDialog = false },
|
||||
title = { Text("出牌记录", color = Color(0xFF333333), fontWeight = FontWeight.Bold) },
|
||||
text = {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.heightIn(min = 300.dp, max = 420.dp)
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
if (gameLog.isEmpty()) {
|
||||
Text("暂无记录", color = dimText, fontSize = 13.sp)
|
||||
}
|
||||
gameLog.forEachIndexed { index, msg ->
|
||||
val playerName = gameLogPlayers.getOrElse(index) { parsePlayerName(msg) }
|
||||
val avatar = getBotAvatar(playerName)
|
||||
val colorText = parseColorText(msg)
|
||||
val cardColor = cardColorMap[colorText]
|
||||
val isPlay = " 出了 " in msg
|
||||
val arrowColor = parseArrowColor(msg)
|
||||
val afterPlayer = msg.substringAfter(playerName)
|
||||
|
||||
// 用 AnnotatedString 构建整行,支持自动换行
|
||||
val annotated = buildAnnotatedString {
|
||||
// 序号
|
||||
withStyle(SpanStyle(color = Color(0xFF999999), fontSize = 13.sp)) {
|
||||
append("${gameLog.size - index}. ")
|
||||
}
|
||||
// 玩家名
|
||||
withStyle(SpanStyle(color = avatar.color, fontWeight = FontWeight.Bold, fontSize = 13.sp)) {
|
||||
append(playerName)
|
||||
}
|
||||
if (isPlay && (colorText.isNotEmpty() || arrowColor != null)) {
|
||||
if (arrowColor != null) {
|
||||
val prefix = afterPlayer.substringBefore(" 万能")
|
||||
val cardBlock = afterPlayer.substringAfter(" 出了 ").substringBefore(",")
|
||||
val remain = afterPlayer.substringAfter(prefix + " 出了 " + cardBlock)
|
||||
withStyle(SpanStyle(color = dimText, fontSize = 13.sp)) {
|
||||
append(prefix)
|
||||
append(" 出了 ")
|
||||
}
|
||||
withStyle(SpanStyle(color = Color.Black, fontWeight = FontWeight.Black,
|
||||
fontSize = 13.sp, background = arrowColor.second.copy(alpha = 0.9f))) {
|
||||
append(cardBlock)
|
||||
}
|
||||
if (remain.isNotEmpty()) {
|
||||
withStyle(SpanStyle(color = Color(0xFF777777), fontSize = 12.sp)) {
|
||||
append(remain)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val prefix = afterPlayer.substringBefore(colorText)
|
||||
val cardId = colorText + afterPlayer.substringAfter(colorText).substringBefore(",")
|
||||
val remain = afterPlayer.substringAfter(prefix + cardId)
|
||||
withStyle(SpanStyle(color = dimText, fontSize = 13.sp)) {
|
||||
append(prefix)
|
||||
}
|
||||
withStyle(SpanStyle(color = Color.Black, fontWeight = FontWeight.Black,
|
||||
fontSize = 13.sp, background = (cardColor ?: Color.Gray).copy(alpha = 0.9f))) {
|
||||
append(cardId)
|
||||
}
|
||||
if (remain.isNotEmpty()) {
|
||||
withStyle(SpanStyle(color = Color(0xFF777777), fontSize = 12.sp)) {
|
||||
append(remain)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
withStyle(SpanStyle(color = dimText, fontSize = 13.sp)) {
|
||||
append(afterPlayer)
|
||||
}
|
||||
}
|
||||
}
|
||||
Text(annotated, modifier = Modifier.padding(vertical = 5.dp))
|
||||
// 条目间加细分割线
|
||||
if (index < gameLog.size - 1) {
|
||||
Spacer(modifier = Modifier.height(1.dp))
|
||||
title = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("出牌记录", color = Color(0xFF333333), fontWeight = FontWeight.Bold, modifier = Modifier.weight(1f))
|
||||
if (gameLog.size > 4 && canScrollBackward) {
|
||||
var topPressed by remember { mutableStateOf(false) }
|
||||
val topScale by animateFloatAsState(if (topPressed) 1.4f else 1f, spring())
|
||||
if (topPressed) {
|
||||
LaunchedEffect(Unit) { kotlinx.coroutines.delay(400); topPressed = false }
|
||||
}
|
||||
IconButton(
|
||||
onClick = { topPressed = true; scope.launch { listState.animateScrollToItem(0) } },
|
||||
modifier = Modifier.size(28.dp).scale(topScale)
|
||||
) { Icon(Icons.Default.KeyboardArrowUp, "到顶部", tint = Color(0xFF555555)) }
|
||||
} else {
|
||||
Spacer(modifier = Modifier.size(28.dp)) // 占位保持标题居中
|
||||
}
|
||||
}
|
||||
},
|
||||
text = {
|
||||
// 记录内容
|
||||
if (gameLog.isEmpty()) {
|
||||
Text("暂无记录", color = dimText, fontSize = 13.sp)
|
||||
} else {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(450.dp)
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
// 滚动内容(纯文字区域)
|
||||
LazyColumn(
|
||||
state = listState,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
itemsIndexed(gameLog) { index, msg ->
|
||||
val playerName = gameLogPlayers.getOrElse(index) { parsePlayerName(msg) }
|
||||
val avatar = getBotAvatar(playerName)
|
||||
val colorText = parseColorText(msg)
|
||||
val cardColor = cardColorMap[colorText]
|
||||
val isPlay = " 出了 " in msg
|
||||
val arrowColor = parseArrowColor(msg)
|
||||
val afterPlayer = msg.substringAfter(playerName)
|
||||
|
||||
val annotated = buildAnnotatedString {
|
||||
withStyle(SpanStyle(color = Color(0xFF999999), fontSize = 13.sp)) {
|
||||
append("${gameLog.size - index}. ")
|
||||
}
|
||||
withStyle(SpanStyle(color = avatar.color, fontWeight = FontWeight.Bold, fontSize = 13.sp)) {
|
||||
append(playerName)
|
||||
}
|
||||
if (isPlay && (colorText.isNotEmpty() || arrowColor != null)) {
|
||||
if (arrowColor != null) {
|
||||
val prefix = afterPlayer.substringBefore(" 万能")
|
||||
val cardBlock = afterPlayer.substringAfter(" 出了 ").substringBefore(",")
|
||||
val remain = afterPlayer.substringAfter(prefix + " 出了 " + cardBlock)
|
||||
withStyle(SpanStyle(color = dimText, fontSize = 13.sp)) {
|
||||
append(prefix); append(" 出了 ")
|
||||
}
|
||||
withStyle(SpanStyle(color = Color.Black, fontWeight = FontWeight.Black,
|
||||
fontSize = 13.sp, background = arrowColor.second.copy(alpha = 0.9f))) {
|
||||
append(cardBlock)
|
||||
}
|
||||
if (remain.isNotEmpty()) {
|
||||
withStyle(SpanStyle(color = Color(0xFF777777), fontSize = 12.sp)) {
|
||||
append(remain)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val prefix = afterPlayer.substringBefore(colorText)
|
||||
val cardId = colorText + afterPlayer.substringAfter(colorText).substringBefore(",")
|
||||
val remain = afterPlayer.substringAfter(prefix + cardId)
|
||||
withStyle(SpanStyle(color = dimText, fontSize = 13.sp)) {
|
||||
append(prefix)
|
||||
}
|
||||
withStyle(SpanStyle(color = Color.Black, fontWeight = FontWeight.Black,
|
||||
fontSize = 13.sp, background = (cardColor ?: Color.Gray).copy(alpha = 0.9f))) {
|
||||
append(cardId)
|
||||
}
|
||||
if (remain.isNotEmpty()) {
|
||||
withStyle(SpanStyle(color = Color(0xFF777777), fontSize = 12.sp)) {
|
||||
append(remain)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
withStyle(SpanStyle(color = dimText, fontSize = 13.sp)) {
|
||||
append(afterPlayer)
|
||||
}
|
||||
}
|
||||
}
|
||||
Text(annotated, modifier = Modifier.padding(vertical = 5.dp))
|
||||
}
|
||||
}
|
||||
|
||||
} // Box 结束
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = { showLogDialog = false }) {
|
||||
Text("关闭", color = Color(0xFF333333))
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
if (canScrollForward) {
|
||||
var bottomPressed by remember { mutableStateOf(false) }
|
||||
val bottomScale by animateFloatAsState(if (bottomPressed) 1.4f else 1f, spring())
|
||||
if (bottomPressed) {
|
||||
LaunchedEffect(Unit) { kotlinx.coroutines.delay(400); bottomPressed = false }
|
||||
}
|
||||
IconButton(
|
||||
onClick = { bottomPressed = true; scope.launch { listState.animateScrollToItem(gameLog.size - 1) } },
|
||||
modifier = Modifier.size(28.dp).scale(bottomScale)
|
||||
) { Icon(Icons.Default.KeyboardArrowDown, "到底部", tint = Color(0xFF555555)) }
|
||||
} else {
|
||||
Spacer(modifier = Modifier.size(28.dp))
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
TextButton(onClick = { showLogDialog = false }) {
|
||||
Text("关闭", color = Color(0xFF333333))
|
||||
}
|
||||
}
|
||||
},
|
||||
containerColor = creamBg
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user