diff --git a/app/src/main/java/com/aiosman/ravenow/ui/account/MbtiSelectScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/account/MbtiSelectScreen.kt index c7b324e..77ba98b 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/account/MbtiSelectScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/account/MbtiSelectScreen.kt @@ -20,11 +20,13 @@ import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable @@ -47,6 +49,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.aiosman.ravenow.AppState @@ -104,206 +107,202 @@ fun MbtiSelectBottomSheet( } else { Color(0xFFFFFFFF) } - - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - - // 确保弹窗展开 - LaunchedEffect(Unit) { - sheetState.expand() - } - - // 监听状态变化,确保弹窗始终展开(防止拖拽关闭和滑动) - LaunchedEffect(sheetState.currentValue, sheetState.targetValue, sheetState.isVisible) { - // 如果弹窗被拖拽关闭或位置发生变化,立即重新展开 - if (!sheetState.isVisible || sheetState.targetValue != androidx.compose.material3.SheetValue.Expanded) { - kotlinx.coroutines.delay(10) // 短暂延迟确保状态更新 - sheetState.expand() - } - } - val statusBarPadding = WindowInsets.systemBars.asPaddingValues() - val configuration = LocalConfiguration.current - val screenHeight = configuration.screenHeightDp.dp - val offsetY = screenHeight * 0.07f - statusBarPadding.calculateTopPadding() - + val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + ModalBottomSheet( onDismissRequest = onClose, sheetState = sheetState, - containerColor = sheetBackgroundColor, - dragHandle = null + containerColor = Color.Transparent, + shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), + dragHandle = {} ) { Box( modifier = Modifier .fillMaxWidth() - .fillMaxHeight(0.95f) - .offset(y = offsetY) - .padding( - start = 16.dp, - end = 16.dp, - bottom = 8.dp - ) + .fillMaxHeight() + .padding(top = 8.dp) ) { - Column( + Surface( modifier = Modifier .fillMaxWidth() .fillMaxHeight() + .clip(RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)), + color = sheetBackgroundColor, + tonalElevation = 0.dp, + shadowElevation = 0.dp, ) { - // 头部 - 使用 Box 实现绝对居中布局 - Box( + Column( modifier = Modifier .fillMaxWidth() - .height(48.dp), - contentAlignment = Alignment.Center + .fillMaxHeight() + .padding(horizontal = 16.dp, vertical = 8.dp) ) { - val cancelButtonGradientColors = if (isDarkMode) { - listOf( - Color(0xFF3A3A3C), - Color(0xFF2C2C2E) - ) - } else { - listOf( - Color(0xFFFFFFFF), - Color(0xFFF8F8F8) - ) - } - val cancelButtonContentColor = if (isDarkMode) Color(0xFFFFFFFF) else Color(0xFF404040) - - // 左上角返回按钮 - Row( + // 头部 + Box( modifier = Modifier - .align(Alignment.CenterStart) - .height(36.dp) - .clip(RoundedCornerShape(18.dp)) - .background( - brush = Brush.linearGradient( - colors = cancelButtonGradientColors - ) - ) - .noRippleClickable { onClose() } - .padding(horizontal = 8.dp), - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically + .fillMaxWidth() + .height(48.dp), + contentAlignment = Alignment.Center ) { - // 左箭头图标 - Image( - painter = painterResource(id = R.drawable.rider_pro_back_icon), - contentDescription = null, - modifier = Modifier.size(17.dp), - colorFilter = ColorFilter.tint(cancelButtonContentColor) - ) - - // "取消" 文字 - Text( - text = "取消", - fontSize = 17.sp, - fontWeight = FontWeight.Medium, - color = cancelButtonContentColor, - textAlign = androidx.compose.ui.text.style.TextAlign.Center - ) - } - - // 中间标题 - 绝对居中 - Text( - text = stringResource(R.string.choose_mbti), - color = appColors.text, - fontSize = 20.sp, - fontWeight = FontWeight.Bold, - textAlign = androidx.compose.ui.text.style.TextAlign.Center - ) - } - - Spacer(Modifier.height(12.dp)) - - // 创建 NestedScrollConnection 来阻止滚动事件向上传播到 ModalBottomSheet - val nestedScrollConnection = remember { - object : NestedScrollConnection { - override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { - // 不消费任何事件,让 LazyColumn 先处理 - return Offset.Zero + val cancelButtonGradientColors = if (isDarkMode) { + listOf( + Color(0xFF3A3A3C), + Color(0xFF2C2C2E) + ) + } else { + listOf( + Color(0xFFFFFFFF), + Color(0xFFF8F8F8) + ) } + val cancelButtonContentColor = if (isDarkMode) Color(0xFFFFFFFF) else Color(0xFF404040) - override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset { - // 消费 LazyColumn 处理后的剩余滚动事件,防止传递到 ModalBottomSheet - return available - } - - override suspend fun onPreFling(available: Velocity): Velocity { - // 不消费惯性滚动,让 LazyColumn 先处理 - return Velocity.Zero - } - - override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { - // 消费 LazyColumn 处理后的剩余惯性滚动,防止传递到 ModalBottomSheet - return available - } - } - } - - // MBTI解释文字背景色 - val descriptionBackgroundColor = if (isDarkMode) { - Color(0xFF2A2A2A) // 比 secondaryBackground (0xFF1C1C1C) 更亮的灰色 - } else { - Color(0xFFFAF9FB) - } - - // 使用LazyColumn包裹解释文字和MBTI类型网格,使它们一起滚动 - LazyColumn( - modifier = Modifier - .fillMaxWidth() - .weight(1f) - .nestedScroll(nestedScrollConnection), - contentPadding = PaddingValues( - start = 8.dp, - top = 0.dp, - end = 8.dp, - bottom = 8.dp - ), - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { - // MBTI解释文字 - 作为第一个item - item { + // 左上角返回按钮:整体「箭头 + 取消」在按钮内居中 Box( modifier = Modifier - .fillMaxWidth() - .clip(RoundedCornerShape(16.dp)) - .background(descriptionBackgroundColor) - .padding(horizontal = 16.dp, vertical = 12.dp) + .align(Alignment.CenterStart) + .width(91.dp) + .height(44.dp) + .clip(RoundedCornerShape(1000.dp)) + .background( + brush = Brush.linearGradient( + colors = cancelButtonGradientColors + ) + ) + .noRippleClickable { onClose() }, + contentAlignment = Alignment.Center ) { - Text( - text = stringResource(R.string.mbti_description), - color = appColors.text, - fontSize = 14.sp, - lineHeight = 20.sp - ) + Row( + modifier = Modifier + .padding(horizontal = 12.dp, vertical = 4.dp), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(id = R.drawable.rider_pro_back_icon), + contentDescription = null, + modifier = Modifier.size(17.dp), + colorFilter = ColorFilter.tint(cancelButtonContentColor) + ) + + Spacer(modifier = Modifier.width(4.dp)) + + Text( + text = "取消", + fontSize = 17.sp, + fontWeight = FontWeight.Medium, + color = cancelButtonContentColor, + textAlign = TextAlign.Center, + maxLines = 1, + overflow = TextOverflow.Clip + ) + } + } + + // 中间标题 + Text( + text = stringResource(R.string.choose_mbti), + color = appColors.text, + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center + ) + } + + Spacer(Modifier.height(12.dp)) + + // NestedScroll,阻止滚动事件向上传到 BottomSheet + val nestedScrollConnection = remember { + object : NestedScrollConnection { + override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + return Offset.Zero + } + + override fun onPostScroll( + consumed: Offset, + available: Offset, + source: NestedScrollSource + ): Offset { + return available + } + + override suspend fun onPreFling(available: Velocity): Velocity { + return Velocity.Zero + } + + override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { + return available + } } } - // MBTI类型网格 - 手动创建2列网格布局 - itemsIndexed(MBTI_TYPES.chunked(2)) { rowIndex, rowItems -> - Row( - modifier = Modifier - .fillMaxWidth() - .padding(bottom = if (rowIndex < MBTI_TYPES.chunked(2).size - 1) 10.dp else 0.dp), - horizontalArrangement = Arrangement.spacedBy(10.dp) - ) { - rowItems.forEachIndexed { colIndex, mbti -> - Box( - modifier = Modifier.weight(1f) - ) { - MbtiItem( - mbti = mbti, - isSelected = mbti == currentMbti, - onClick = { - // 保存MBTI类型 - model.mbti = mbti - onClose() - } - ) - } + val descriptionBackgroundColor = if (isDarkMode) { + Color(0xFF2A2A2A) + } else { + Color(0xFFFAF9FB) + } + + // 列表:上面是说明文字,下面是 MBTI 网格 + LazyColumn( + modifier = Modifier + .fillMaxWidth() + .weight(1f) + .nestedScroll(nestedScrollConnection), + contentPadding = PaddingValues( + start = 8.dp, + top = 0.dp, + end = 8.dp, + bottom = 8.dp + ), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + // 说明文字 + item { + Box( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(16.dp)) + .background(descriptionBackgroundColor) + .padding(horizontal = 16.dp, vertical = 12.dp) + ) { + Text( + text = stringResource(R.string.mbti_description), + color = appColors.text, + fontSize = 14.sp, + lineHeight = 20.sp + ) } - // 如果这一行只有1个item,添加一个空的Spacer来保持布局 - if (rowItems.size == 1) { - Spacer(modifier = Modifier.weight(1f)) + } + + // MBTI 类型网格(2 列) + itemsIndexed(MBTI_TYPES.chunked(2)) { rowIndex, rowItems -> + Row( + modifier = Modifier + .fillMaxWidth() + .padding( + bottom = if (rowIndex < MBTI_TYPES.chunked(2).size - 1) 10.dp else 0.dp + ), + horizontalArrangement = Arrangement.spacedBy(10.dp) + ) { + rowItems.forEach { mbti -> + Box( + modifier = Modifier.weight(1f) + ) { + MbtiItem( + mbti = mbti, + isSelected = mbti == currentMbti, + onClick = { + model.mbti = mbti + onClose() + } + ) + } + } + + if (rowItems.size == 1) { + Spacer(modifier = Modifier.weight(1f)) + } } } } @@ -358,30 +357,26 @@ fun MbtiItem( ) { onClick() } - .padding(horizontal = 24.dp, vertical = 12.dp), + .padding(horizontal = 16.dp, vertical = 12.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { - // MBTI图标 - 使用占位图片 - Box( - modifier = Modifier.size(100.dp), - contentAlignment = Alignment.Center - ) { - Image( - painter = painterResource(id = getMbtiImageResId(mbti, isDarkMode)), - contentDescription = mbti, - modifier = Modifier.size(100.dp) - ) - } - - // MBTI名称 - 使用负间距让文本向上移动,与图标更靠近 + // 直接把 MBTI 图标和文字放在灰色卡片内部,布局与星座保持一致 + Image( + painter = painterResource(id = getMbtiImageResId(mbti, isDarkMode)), + contentDescription = mbti, + modifier = Modifier.size(96.dp) + ) + + Spacer(modifier = Modifier.height(0.dp)) + Text( text = mbti, fontSize = 14.sp, fontWeight = FontWeight.Medium, color = appColors.text, textAlign = TextAlign.Center, - modifier = Modifier.offset(y = (-20).dp) + modifier = Modifier.offset(y = (-10).dp) ) } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/account/ZodiacSelectScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/account/ZodiacSelectScreen.kt index 17290b7..3ed4ba2 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/account/ZodiacSelectScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/account/ZodiacSelectScreen.kt @@ -28,6 +28,7 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable @@ -47,6 +48,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.nestedScroll @@ -134,168 +136,165 @@ fun ZodiacSelectBottomSheet( } val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - - // 确保弹窗展开 - LaunchedEffect(Unit) { - sheetState.expand() - } - - // 监听状态变化,确保弹窗始终展开(防止拖拽关闭和滑动) - LaunchedEffect(sheetState.currentValue, sheetState.targetValue, sheetState.isVisible) { - // 如果弹窗被拖拽关闭或位置发生变化,立即重新展开 - if (!sheetState.isVisible || sheetState.targetValue != androidx.compose.material3.SheetValue.Expanded) { - kotlinx.coroutines.delay(10) // 短暂延迟确保状态更新 - sheetState.expand() - } - } - val statusBarPadding = WindowInsets.systemBars.asPaddingValues() - val configuration = LocalConfiguration.current - val screenHeight = configuration.screenHeightDp.dp - val offsetY = screenHeight * 0.07f - statusBarPadding.calculateTopPadding() - ModalBottomSheet( onDismissRequest = onClose, sheetState = sheetState, - containerColor = sheetBackgroundColor, // 根据主题自适应背景 - dragHandle = null + // 对齐发布动态草稿箱样式:底层透明,内容区域自己绘制圆角和背景 + containerColor = Color.Transparent, + shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), + dragHandle = {} ) { Box( modifier = Modifier .fillMaxWidth() - .fillMaxHeight(0.95f) - .offset(y = offsetY) - .padding( - start = 16.dp, - end = 16.dp, - bottom = 8.dp - ) + .fillMaxHeight() + .padding(top = 8.dp) ) { - Column( + Surface( modifier = Modifier .fillMaxWidth() .fillMaxHeight() + .clip(RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)), + color = sheetBackgroundColor, + tonalElevation = 0.dp, + shadowElevation = 0.dp, ) { - // 头部 - 使用 Box 实现绝对居中布局 - Box( + Column( modifier = Modifier .fillMaxWidth() - .height(48.dp), - contentAlignment = Alignment.Center + .fillMaxHeight() + .padding(horizontal = 16.dp, vertical = 8.dp) ) { - val cancelButtonGradientColors = if (isDarkMode) { - listOf( - Color(0xFF3A3A3C), - Color(0xFF2C2C2E) - ) - } else { - listOf( - Color(0xFFFFFFFF), - Color(0xFFF8F8F8) - ) - } - val cancelButtonContentColor = if (isDarkMode) Color(0xFFFFFFFF) else Color(0xFF404040) - - // 左上角返回按钮 - 根据 Swift 代码样式,带淡灰色渐变背景 - Row( + // 头部 - 使用 Box 实现绝对居中布局(对齐草稿箱样式) + Box( modifier = Modifier - .align(Alignment.CenterStart) - .height(36.dp) - .clip(RoundedCornerShape(18.dp)) // 圆角 100.0 在 36dp 高度下接近完全圆角 - .background( - brush = Brush.linearGradient( - colors = cancelButtonGradientColors - // 不指定 start 和 end,默认从左上到右下 - ) - ) - .noRippleClickable { onClose() } - .padding(horizontal = 8.dp), // 内部 padding 确保内容不贴边 - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically + .fillMaxWidth() + .height(48.dp), + contentAlignment = Alignment.Center ) { - // 左箭头图标 - Image( - painter = painterResource(id = R.drawable.rider_pro_back_icon), - contentDescription = null, - modifier = Modifier.size(17.dp), - colorFilter = ColorFilter.tint(cancelButtonContentColor) - ) + val cancelButtonGradientColors = if (isDarkMode) { + listOf( + Color(0xFF3A3A3C), + Color(0xFF2C2C2E) + ) + } else { + listOf( + Color(0xFFFFFFFF), + Color(0xFFF8F8F8) + ) + } + val cancelButtonContentColor = if (isDarkMode) Color(0xFFFFFFFF) else Color(0xFF404040) + + // 左上角返回按钮:参考 iOS 设计,整体「箭头 + 取消」在 91x44 的按钮内居中 + Box( + modifier = Modifier + .align(Alignment.CenterStart) + .width(91.dp) + .height(44.dp) + .clip(RoundedCornerShape(1000.dp)) + .background( + brush = Brush.linearGradient( + colors = cancelButtonGradientColors + ) + ) + .noRippleClickable { onClose() }, + contentAlignment = Alignment.Center + ) { + Row( + modifier = Modifier + // 不再固定宽度,让内容自然占位,避免裁剪掉“消”字 + .padding(horizontal = 12.dp, vertical = 4.dp), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(id = R.drawable.rider_pro_back_icon), + contentDescription = null, + modifier = Modifier.size(17.dp), + colorFilter = ColorFilter.tint(cancelButtonContentColor) + ) + + Spacer(modifier = Modifier.width(4.dp)) + + Text( + text = "取消", + fontSize = 17.sp, + fontWeight = FontWeight.Medium, + color = cancelButtonContentColor, + textAlign = androidx.compose.ui.text.style.TextAlign.Center, + maxLines = 1, + overflow = TextOverflow.Clip + ) + } + } - // "取消" 文字 Text( - text = "取消", - fontSize = 17.sp, - fontWeight = FontWeight.Medium, - color = cancelButtonContentColor, + text = stringResource(R.string.choose_zodiac), + color = appColors.text, + fontSize = 20.sp, + fontWeight = FontWeight.Bold, textAlign = androidx.compose.ui.text.style.TextAlign.Center ) } - - // 中间标题 - 绝对居中 - Text( - text = stringResource(R.string.choose_zodiac), - color = appColors.text, - fontSize = 20.sp, - fontWeight = FontWeight.Bold, - textAlign = androidx.compose.ui.text.style.TextAlign.Center - ) - } - Spacer(Modifier.height(12.dp)) + Spacer(Modifier.height(12.dp)) - // 创建 NestedScrollConnection 来阻止滚动事件向上传播到 ModalBottomSheet - val nestedScrollConnection = remember { - object : NestedScrollConnection { - override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { - // 不消费任何事件,让 LazyVerticalGrid 先处理 - return Offset.Zero - } + // 创建 NestedScrollConnection: + // 1. 不抢在列表前面消费事件,让 LazyVerticalGrid 正常滚动 + // 2. 在列表滚动之后把剩余滚动吃掉,避免继续传递到 BottomSheet 去触发下拉关闭 + val nestedScrollConnection = remember { + object : NestedScrollConnection { + override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + // 不在这里消费,先让 LazyVerticalGrid 自己处理滚动 + return Offset.Zero + } - override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset { - // 消费 LazyVerticalGrid 处理后的剩余滚动事件,防止传递到 ModalBottomSheet - return available - } + override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset { + // 列表滚动完之后,把剩余滚动(尤其是向下拖拽)全部吃掉,防止再传给 BottomSheet + return available + } - override suspend fun onPreFling(available: Velocity): Velocity { - // 不消费惯性滚动,让 LazyVerticalGrid 先处理 - return Velocity.Zero - } + override suspend fun onPreFling(available: Velocity): Velocity { + // 不抢在列表前面处理 fling,让 LazyVerticalGrid 先做惯性滚动 + return Velocity.Zero + } - override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { - // 消费 LazyVerticalGrid 处理后的剩余惯性滚动,防止传递到 ModalBottomSheet - return available + override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { + // 列表惯性滚动之后,把剩余的 fling 速度吃掉,避免带动 BottomSheet 下滑关闭 + return available + } } } - } - // 网格列表 - 2列 - LazyVerticalGrid( - columns = GridCells.Fixed(2), - modifier = Modifier - .fillMaxWidth() - .weight(1f) - .nestedScroll(nestedScrollConnection), - contentPadding = PaddingValues( - start = 8.dp, - top = 8.dp, - end = 8.dp, - bottom = 8.dp - ), - horizontalArrangement = Arrangement.spacedBy(10.dp), - verticalArrangement = Arrangement.spacedBy(10.dp) - ) { - itemsIndexed(ZODIAC_SIGN_RES_IDS) { index, zodiacResId -> - val zodiacText = stringResource(zodiacResId) - ZodiacItem( - zodiac = zodiacText, - zodiacResId = zodiacResId, - isSelected = zodiacResId == currentZodiacResId, - onClick = { - // 保存当前语言的星座文本 - model.zodiac = zodiacText - onClose() - } - ) + // 网格列表 - 2列(与草稿箱一样放在内容区域内部滚动) + LazyVerticalGrid( + columns = GridCells.Fixed(2), + modifier = Modifier + .fillMaxWidth() + .weight(1f) + .nestedScroll(nestedScrollConnection), + contentPadding = PaddingValues( + start = 8.dp, + top = 8.dp, + end = 8.dp, + bottom = 8.dp + ), + horizontalArrangement = Arrangement.spacedBy(10.dp), + verticalArrangement = Arrangement.spacedBy(10.dp) + ) { + itemsIndexed(ZODIAC_SIGN_RES_IDS) { index, zodiacResId -> + val zodiacText = stringResource(zodiacResId) + ZodiacItem( + zodiac = zodiacText, + zodiacResId = zodiacResId, + isSelected = zodiacResId == currentZodiacResId, + onClick = { + model.zodiac = zodiacText + onClose() + } + ) + } } } } @@ -336,9 +335,9 @@ fun ZodiacItem( Column( modifier = Modifier .fillMaxWidth() - .aspectRatio(1.1f) // 增加宽高比,使高度相对更低 + .aspectRatio(1.1f) .shadow( - elevation = if (isDarkMode) 8.dp else 2.dp, // 深色模式下更强的阴影 + elevation = if (isDarkMode) 8.dp else 2.dp, shape = RoundedCornerShape(21.dp), spotColor = if (isDarkMode) Color.Black.copy(alpha = 0.5f) else Color.Black.copy(alpha = 0.1f) ) @@ -350,30 +349,27 @@ fun ZodiacItem( ) { onClick() } - .padding(horizontal = 24.dp, vertical = 12.dp), // 减小垂直padding,确保文本不被遮挡 + .padding(horizontal = 16.dp, vertical = 12.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { - // 星座图标 - 使用对应星座的图片 - Box( - modifier = Modifier.size(100.dp), - contentAlignment = Alignment.Center - ) { - Image( - painter = painterResource(id = getZodiacImageResId(zodiacResId)), - contentDescription = zodiac, - modifier = Modifier.size(100.dp) - ) - } - - // 星座名称 - 使用负间距让文本向上移动,与图标更靠近 + // 直接把图标和文字放在灰色卡片内部,不再额外嵌套一层 Box + Image( + painter = painterResource(id = getZodiacImageResId(zodiacResId)), + contentDescription = zodiac, + // 图标稍微放大一些,让视觉更聚焦在星座图标上 + modifier = Modifier.size(96.dp) + ) + + Spacer(modifier = Modifier.height(0.dp)) + Text( text = zodiac, fontSize = 14.sp, fontWeight = FontWeight.Medium, color = appColors.text, textAlign = TextAlign.Center, - modifier = Modifier.offset(y = (-20).dp) // 负间距,让文本进一步向上移动 + modifier = Modifier.offset(y = (-10).dp) // 再整体向上偏移 5dp(共 10dp) ) } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentModal.kt b/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentModal.kt index 4f69723..ad98fa2 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentModal.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentModal.kt @@ -17,6 +17,7 @@ import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider @@ -29,6 +30,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -40,6 +42,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import kotlinx.coroutines.launch import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope @@ -107,6 +110,8 @@ fun CommentModalContent( var softwareKeyboardController = LocalSoftwareKeyboardController.current var replyComment by remember { mutableStateOf(null) } var shouldAutoFocus by remember { mutableStateOf(false) } + val listState = rememberLazyListState() + val scope = rememberCoroutineScope() LaunchedEffect(imePadding) { bottomPadding = imePadding.dp @@ -213,6 +218,9 @@ fun CommentModalContent( ) { commentViewModel.order = it commentViewModel.reloadComment() + scope.launch { + listState.scrollToItem(0) + } } } Box( @@ -223,7 +231,8 @@ fun CommentModalContent( LazyColumn( modifier = Modifier .fillMaxSize() - .padding(horizontal = 16.dp) + .padding(horizontal = 16.dp), + state = listState ) { item { CommentContent( diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/news/NewsCommentModal.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/news/NewsCommentModal.kt index b6b79e2..56484cd 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/news/NewsCommentModal.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/news/NewsCommentModal.kt @@ -17,6 +17,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close @@ -30,6 +31,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -144,6 +146,8 @@ fun NewsCommentModal( var showCommentMenu by remember { mutableStateOf(false) } var contextComment by remember { mutableStateOf(null) } var replyComment by remember { mutableStateOf(null) } + val listState = rememberLazyListState() + val scope = rememberCoroutineScope() // 菜单弹窗 if (showCommentMenu) { @@ -231,6 +235,9 @@ fun NewsCommentModal( ) { commentViewModel.order = it commentViewModel.reloadComment() + scope.launch { + listState.scrollToItem(0) + } } } } @@ -269,7 +276,9 @@ fun NewsCommentModal( ) } } else { - LazyColumn { + LazyColumn( + state = listState + ) { item { CommentContent( viewModel = commentViewModel, diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/recommend/VideoRecommendationItem.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/recommend/VideoRecommendationItem.kt index cc663bd..4dbebdb 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/recommend/VideoRecommendationItem.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/recommend/VideoRecommendationItem.kt @@ -347,6 +347,11 @@ fun VideoRecommendationItem( if (isVisible && shouldResumeAfterLifecyclePause) { pauseIconVisibleState = false exoPlayer.play() + } else { + // 未自动恢复播放时,如果当前可见且视频已暂停,则显示暂停图标 + if (isVisible && !exoPlayer.isPlaying) { + pauseIconVisibleState = true + } } } else -> {} diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/shorts/ShortViewCompose.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/shorts/ShortViewCompose.kt index 21375d6..05efdaf 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/shorts/ShortViewCompose.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/shorts/ShortViewCompose.kt @@ -549,6 +549,11 @@ fun VideoPlayer( exoPlayer.playWhenReady = true exoPlayer.play() pauseIconVisibleState.value = false + } else { + // 未自动恢复播放时,如果当前页面视频处于暂停状态,则显示暂停图标 + if (!exoPlayer.isPlaying) { + pauseIconVisibleState.value = true + } } }