Merge branch 'main' into atm2
@@ -0,0 +1,15 @@
|
||||
package com.aiosman.ravenow.ui.account
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
|
||||
@Composable
|
||||
fun ZodiacBottomSheetHost() {
|
||||
val show = ZodiacSheetManager.visible.collectAsState(false).value
|
||||
if (show) {
|
||||
ZodiacSelectBottomSheet(
|
||||
onClose = { ZodiacSheetManager.close() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +1,64 @@
|
||||
package com.aiosman.ravenow.ui.account
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.itemsIndexed
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
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.input.nestedscroll.NestedScrollConnection
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.unit.Velocity
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import com.aiosman.ravenow.AppState
|
||||
import com.aiosman.ravenow.LocalAppTheme
|
||||
import com.aiosman.ravenow.LocalNavController
|
||||
import com.aiosman.ravenow.R
|
||||
import com.aiosman.ravenow.ui.comment.NoticeScreenHeader
|
||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
|
||||
// 星座资源ID列表
|
||||
val ZODIAC_SIGN_RES_IDS = listOf(
|
||||
@@ -51,6 +76,27 @@ val ZODIAC_SIGN_RES_IDS = listOf(
|
||||
R.string.zodiac_pisces
|
||||
)
|
||||
|
||||
/**
|
||||
* 根据星座资源ID获取对应的图片资源ID
|
||||
*/
|
||||
fun getZodiacImageResId(zodiacResId: Int): Int {
|
||||
return when (zodiacResId) {
|
||||
R.string.zodiac_aries -> R.mipmap.baiyang
|
||||
R.string.zodiac_taurus -> R.mipmap.jingniu
|
||||
R.string.zodiac_gemini -> R.mipmap.shuangzi
|
||||
R.string.zodiac_cancer -> R.mipmap.juxie
|
||||
R.string.zodiac_leo -> R.mipmap.shizi
|
||||
R.string.zodiac_virgo -> R.mipmap.chunv
|
||||
R.string.zodiac_libra -> R.mipmap.tiancheng
|
||||
R.string.zodiac_scorpio -> R.mipmap.tianxie
|
||||
R.string.zodiac_sagittarius -> R.mipmap.sheshou
|
||||
R.string.zodiac_capricorn -> R.mipmap.moxie
|
||||
R.string.zodiac_aquarius -> R.mipmap.shuiping
|
||||
R.string.zodiac_pisces -> R.mipmap.shuangyu
|
||||
else -> R.mipmap.xingzuo // 默认使用占位图片
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据存储的星座字符串(可能是任何语言)找到对应的资源ID
|
||||
* 如果找不到,返回null
|
||||
@@ -72,58 +118,207 @@ fun findZodiacResId(storedZodiac: String?): Int? {
|
||||
return null
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ZodiacSelectScreen() {
|
||||
val navController = LocalNavController.current
|
||||
fun ZodiacSelectBottomSheet(
|
||||
onClose: () -> Unit
|
||||
) {
|
||||
val appColors = LocalAppTheme.current
|
||||
val isDarkMode = AppState.darkMode
|
||||
val model = AccountEditViewModel
|
||||
val currentZodiacResId = findZodiacResId(model.zodiac)
|
||||
val sheetBackgroundColor = if (isDarkMode) {
|
||||
appColors.secondaryBackground
|
||||
} else {
|
||||
Color(0xFFFFFFFF)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(appColors.profileBackground)
|
||||
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
|
||||
) {
|
||||
// 头部
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 16.dp)
|
||||
) {
|
||||
NoticeScreenHeader(
|
||||
title = stringResource(R.string.choose_zodiac),
|
||||
moreIcon = false
|
||||
)
|
||||
}
|
||||
|
||||
// 列表
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = androidx.compose.foundation.layout.PaddingValues(horizontal = 16.dp, vertical = 8.dp)
|
||||
) {
|
||||
items(ZODIAC_SIGN_RES_IDS.size) { index ->
|
||||
val zodiacResId = ZODIAC_SIGN_RES_IDS[index]
|
||||
val zodiacText = stringResource(zodiacResId)
|
||||
ZodiacItem(
|
||||
zodiac = zodiacText,
|
||||
zodiacResId = zodiacResId,
|
||||
isSelected = zodiacResId == currentZodiacResId,
|
||||
onClick = {
|
||||
// 保存当前语言的星座文本
|
||||
model.zodiac = zodiacText
|
||||
// 立即保存到本地存储,确保选择后立即生效
|
||||
AppState.UserId?.let { uid ->
|
||||
com.aiosman.ravenow.AppStore.setUserZodiac(uid, zodiacText)
|
||||
}
|
||||
navController.navigateUp()
|
||||
}
|
||||
.fillMaxHeight(0.95f)
|
||||
.offset(y = offsetY)
|
||||
.padding(
|
||||
start = 16.dp,
|
||||
end = 16.dp,
|
||||
bottom = 8.dp
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight()
|
||||
) {
|
||||
// 头部 - 使用 Box 实现绝对居中布局
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(48.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
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(
|
||||
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
|
||||
) {
|
||||
// 左箭头图标
|
||||
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_zodiac),
|
||||
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 {
|
||||
// 不消费任何事件,让 LazyVerticalGrid 先处理
|
||||
return Offset.Zero
|
||||
}
|
||||
|
||||
override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset {
|
||||
// 消费 LazyVerticalGrid 处理后的剩余滚动事件,防止传递到 ModalBottomSheet
|
||||
return available
|
||||
}
|
||||
|
||||
override suspend fun onPreFling(available: Velocity): Velocity {
|
||||
// 不消费惯性滚动,让 LazyVerticalGrid 先处理
|
||||
return Velocity.Zero
|
||||
}
|
||||
|
||||
override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
|
||||
// 消费 LazyVerticalGrid 处理后的剩余惯性滚动,防止传递到 ModalBottomSheet
|
||||
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
|
||||
// 立即保存到本地存储,确保选择后立即生效
|
||||
AppState.UserId?.let { uid ->
|
||||
com.aiosman.ravenow.AppStore.setUserZodiac(uid, zodiacText)
|
||||
}
|
||||
onClose()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 保留原有的 ZodiacSelectScreen 用于导航路由(如果需要)
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ZodiacSelectScreen() {
|
||||
val navController = com.aiosman.ravenow.LocalNavController.current
|
||||
ZodiacSelectBottomSheet(
|
||||
onClose = {
|
||||
navController.navigateUp()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ZodiacItem(
|
||||
zodiac: String,
|
||||
@@ -132,41 +327,58 @@ fun ZodiacItem(
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val appColors = LocalAppTheme.current
|
||||
val isDarkMode = AppState.darkMode
|
||||
|
||||
Box(
|
||||
// 卡片背景色:浅灰色 (250, 249, 251)
|
||||
// 暗色模式下使用比背景色更亮的颜色,以形成对比
|
||||
val cardBackgroundColor = if (isDarkMode) {
|
||||
Color(0xFF2A2A2A) // 比 secondaryBackground (0xFF1C1C1C) 更亮的灰色
|
||||
} else {
|
||||
Color(0xFFFAF9FB)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(if (isSelected) appColors.main.copy(alpha = 0.1f) else Color.White)
|
||||
.aspectRatio(1.1f) // 增加宽高比,使高度相对更低
|
||||
.shadow(
|
||||
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)
|
||||
)
|
||||
.clip(RoundedCornerShape(21.dp))
|
||||
.background(cardBackgroundColor)
|
||||
.clickable(
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
) {
|
||||
onClick()
|
||||
}
|
||||
.padding(16.dp)
|
||||
.padding(horizontal = 24.dp, vertical = 12.dp), // 减小垂直padding,确保文本不被遮挡
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
// 星座图标 - 使用对应星座的图片
|
||||
Box(
|
||||
modifier = Modifier.size(100.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = zodiac,
|
||||
fontSize = 17.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = if (isSelected) appColors.main else appColors.text,
|
||||
modifier = Modifier.weight(1f)
|
||||
Image(
|
||||
painter = painterResource(id = getZodiacImageResId(zodiacResId)),
|
||||
contentDescription = zodiac,
|
||||
modifier = Modifier.size(100.dp)
|
||||
)
|
||||
|
||||
if (isSelected) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Check,
|
||||
contentDescription = "Selected",
|
||||
modifier = Modifier.size(20.dp),
|
||||
tint = appColors.main
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 星座名称 - 使用负间距让文本向上移动,与图标更靠近
|
||||
Text(
|
||||
text = zodiac,
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = appColors.text,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.offset(y = (-20).dp) // 负间距,让文本进一步向上移动
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.aiosman.ravenow.ui.account
|
||||
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
object ZodiacSheetManager {
|
||||
private val _visible = MutableStateFlow(false)
|
||||
val visible: StateFlow<Boolean> = _visible.asStateFlow()
|
||||
|
||||
fun open() {
|
||||
_visible.value = true
|
||||
}
|
||||
|
||||
fun close() {
|
||||
_visible.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,8 @@ import com.aiosman.ravenow.ui.composables.pickupAndCompressLauncher
|
||||
import android.widget.Toast
|
||||
import java.io.File
|
||||
import androidx.activity.compose.BackHandler
|
||||
import com.aiosman.ravenow.ui.account.ZodiacBottomSheetHost
|
||||
import com.aiosman.ravenow.ui.account.ZodiacSheetManager
|
||||
|
||||
/**
|
||||
* 编辑用户资料界面
|
||||
@@ -190,6 +192,9 @@ fun AccountEditScreen2(onUpdateBanner: ((Uri, File, Context) -> Unit)? = null,)
|
||||
darkIcons = !AppState.darkMode, // 根据暗色模式决定图标颜色
|
||||
maskBoxBackgroundColor = Color.Transparent
|
||||
) {
|
||||
// 挂载星座选择弹窗
|
||||
ZodiacBottomSheetHost()
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
@@ -448,9 +453,7 @@ fun AccountEditScreen2(onUpdateBanner: ((Uri, File, Context) -> Unit)? = null,)
|
||||
iconResDark = R.mipmap.frame_4, // 星座暗色模式图标
|
||||
iconResLight = R.mipmap.xingzuo, // 星座亮色模式图标
|
||||
onClick = {
|
||||
debouncedNavigation {
|
||||
navController.navigate(NavigationRoute.ZodiacSelect.route)
|
||||
}
|
||||
ZodiacSheetManager.open()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
@@ -34,8 +35,11 @@ import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.rememberTextMeasurer
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewModelScope
|
||||
@@ -565,10 +569,27 @@ fun AddAgentScreen() {
|
||||
.padding(horizontal = 16.dp)
|
||||
.align(Alignment.Start)
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
val textMeasurer = rememberTextMeasurer()
|
||||
val autoLabel = stringResource(R.string.create_agent_auto)
|
||||
val measuredTextWidth = remember(autoLabel, textMeasurer) {
|
||||
textMeasurer.measure(
|
||||
text = AnnotatedString(autoLabel),
|
||||
style = TextStyle(
|
||||
color = appColors.text,
|
||||
fontWeight = FontWeight.W600,
|
||||
fontSize = 14.sp
|
||||
)
|
||||
).size.width
|
||||
}
|
||||
val textWidthDp = with(density) { measuredTextWidth.toDp() }
|
||||
val contentWidth = 24.dp + 18.dp + 8.dp + textWidthDp
|
||||
val boxWidth = if (contentWidth > 140.dp) 250.dp else 140.dp
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Start)
|
||||
.width(140.dp)
|
||||
.width(boxWidth)
|
||||
.height(40.dp)
|
||||
.shadow(
|
||||
elevation = 10.dp,
|
||||
@@ -616,7 +637,7 @@ fun AddAgentScreen() {
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.create_agent_auto),
|
||||
text = autoLabel,
|
||||
color = appColors.text,
|
||||
fontWeight = FontWeight.W600,
|
||||
fontSize = 14.sp
|
||||
|
||||
@@ -21,6 +21,10 @@ import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import com.airbnb.lottie.compose.LottieAnimation
|
||||
import com.airbnb.lottie.compose.LottieCompositionSpec
|
||||
import com.airbnb.lottie.compose.LottieConstants
|
||||
import com.airbnb.lottie.compose.rememberLottieComposition
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -433,10 +437,10 @@ fun AddMemberAiAgentListScreen(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = "加载中...",
|
||||
color = AppColors.secondaryText,
|
||||
fontSize = 14.sp
|
||||
LottieAnimation(
|
||||
composition = rememberLottieComposition(LottieCompositionSpec.Asset("star_Loader.lottie")).value,
|
||||
iterations = LottieConstants.IterateForever,
|
||||
modifier = Modifier.size(80.dp)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@@ -465,10 +469,10 @@ fun AddMemberAiAgentListScreen(
|
||||
.padding(16.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = "加载更多...",
|
||||
color = AppColors.secondaryText,
|
||||
fontSize = 14.sp
|
||||
LottieAnimation(
|
||||
composition = rememberLottieComposition(LottieCompositionSpec.Asset("star_Loader.lottie")).value,
|
||||
iterations = LottieConstants.IterateForever,
|
||||
modifier = Modifier.size(80.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -533,10 +537,10 @@ fun AddMemberFriendListScreen(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = "加载中...",
|
||||
color = AppColors.secondaryText,
|
||||
fontSize = 14.sp
|
||||
LottieAnimation(
|
||||
composition = rememberLottieComposition(LottieCompositionSpec.Asset("star_Loader.lottie")).value,
|
||||
iterations = LottieConstants.IterateForever,
|
||||
modifier = Modifier.size(80.dp)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@@ -565,10 +569,10 @@ fun AddMemberFriendListScreen(
|
||||
.padding(16.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = "加载更多...",
|
||||
color = AppColors.secondaryText,
|
||||
fontSize = 14.sp
|
||||
LottieAnimation(
|
||||
composition = rememberLottieComposition(LottieCompositionSpec.Asset("star_Loader.lottie")).value,
|
||||
iterations = LottieConstants.IterateForever,
|
||||
modifier = Modifier.size(80.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@ import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import com.airbnb.lottie.compose.LottieAnimation
|
||||
import com.airbnb.lottie.compose.LottieCompositionSpec
|
||||
import com.airbnb.lottie.compose.LottieConstants
|
||||
import com.airbnb.lottie.compose.rememberLottieComposition
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
@@ -78,10 +82,10 @@ fun AiAgentListScreen(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = "加载中...",
|
||||
color = AppColors.secondaryText,
|
||||
fontSize = 14.sp
|
||||
LottieAnimation(
|
||||
composition = rememberLottieComposition(LottieCompositionSpec.Asset("star_Loader.lottie")).value,
|
||||
iterations = LottieConstants.IterateForever,
|
||||
modifier = Modifier.size(80.dp)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@@ -111,10 +115,10 @@ fun AiAgentListScreen(
|
||||
.padding(16.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = "加载更多...",
|
||||
color = AppColors.secondaryText,
|
||||
fontSize = 14.sp
|
||||
LottieAnimation(
|
||||
composition = rememberLottieComposition(LottieCompositionSpec.Asset("star_Loader.lottie")).value,
|
||||
iterations = LottieConstants.IterateForever,
|
||||
modifier = Modifier.size(80.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@ import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import com.airbnb.lottie.compose.LottieAnimation
|
||||
import com.airbnb.lottie.compose.LottieCompositionSpec
|
||||
import com.airbnb.lottie.compose.LottieConstants
|
||||
import com.airbnb.lottie.compose.rememberLottieComposition
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
@@ -78,10 +82,10 @@ fun FriendListScreen(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = "加载中...",
|
||||
color = AppColors.secondaryText,
|
||||
fontSize = 14.sp
|
||||
LottieAnimation(
|
||||
composition = rememberLottieComposition(LottieCompositionSpec.Asset("star_Loader.lottie")).value,
|
||||
iterations = LottieConstants.IterateForever,
|
||||
modifier = Modifier.size(80.dp)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@@ -111,10 +115,10 @@ fun FriendListScreen(
|
||||
.padding(16.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = "加载更多...",
|
||||
color = AppColors.secondaryText,
|
||||
fontSize = 14.sp
|
||||
LottieAnimation(
|
||||
composition = rememberLottieComposition(LottieCompositionSpec.Asset("star_Loader.lottie")).value,
|
||||
iterations = LottieConstants.IterateForever,
|
||||
modifier = Modifier.size(80.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,7 +399,7 @@ fun GroupChatInfoScreen(groupId: String) {
|
||||
)
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Text(
|
||||
text = "群资料设置",
|
||||
text = stringResource(R.string.group_chat_info_group_settings),
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text,
|
||||
fontSize = 15.sp
|
||||
|
||||
@@ -41,6 +41,7 @@ import android.widget.Toast
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
||||
@Composable
|
||||
fun GroupMemoryManageContent(
|
||||
@@ -79,7 +80,7 @@ fun GroupMemoryManageContent(
|
||||
) {
|
||||
// 中间标题 - 绝对居中,不受其他组件影响
|
||||
Text(
|
||||
text = "记忆管理",
|
||||
text = stringResource(R.string.group_chat_info_memory_manage2),
|
||||
style = TextStyle(
|
||||
color = Color.Black,
|
||||
fontSize = 17.sp,
|
||||
@@ -107,7 +108,7 @@ fun GroupMemoryManageContent(
|
||||
colorFilter = ColorFilter.tint(Color.Black)
|
||||
)
|
||||
Text(
|
||||
text = "返回",
|
||||
text = stringResource(R.string.back_upper),
|
||||
style = TextStyle(
|
||||
color = Color.Black,
|
||||
fontSize = 15.sp,
|
||||
@@ -148,7 +149,7 @@ fun GroupMemoryManageContent(
|
||||
) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("已付费:", style = TextStyle(color = Color(0x993C3C43), fontSize = 13.sp))
|
||||
Text(stringResource(R.string.memory_paid), style = TextStyle(color = Color(0x993C3C43), fontSize = 13.sp))
|
||||
Spacer(Modifier.width(3.dp))
|
||||
Text(
|
||||
"${quota?.purchasedCount ?: 0}",
|
||||
@@ -156,7 +157,7 @@ fun GroupMemoryManageContent(
|
||||
)
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("已使用:", style = TextStyle(color = Color(0x993C3C43), fontSize = 13.sp))
|
||||
Text(stringResource(R.string.memory_used), style = TextStyle(color = Color(0x993C3C43), fontSize = 13.sp))
|
||||
Spacer(Modifier.width(3.dp))
|
||||
Text(
|
||||
"${quota?.currentCount ?: 0}",
|
||||
@@ -165,7 +166,7 @@ fun GroupMemoryManageContent(
|
||||
}
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("可用上限:", style = TextStyle(color = Color(0x993C3C43), fontSize = 13.sp))
|
||||
Text(stringResource(R.string.upper_limit), style = TextStyle(color = Color(0x993C3C43), fontSize = 13.sp))
|
||||
Spacer(Modifier.width(3.dp))
|
||||
Text(
|
||||
"50",
|
||||
@@ -235,12 +236,12 @@ fun GroupMemoryManageContent(
|
||||
|
||||
Spacer(Modifier.height(10.dp))
|
||||
Text(
|
||||
text = "暂无记忆",
|
||||
text = stringResource(R.string.no_memory),
|
||||
style = TextStyle(color = Color.Black, fontSize = 16.sp, fontWeight = FontWeight.SemiBold)
|
||||
)
|
||||
Spacer(Modifier.height(6.dp))
|
||||
Text(
|
||||
text = "点击上方按钮添加群记忆",
|
||||
text = stringResource(R.string.add_memory),
|
||||
style = TextStyle(color = Color.Black, fontSize = 14.sp, fontWeight = FontWeight.Normal)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
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.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
@@ -574,38 +575,33 @@ fun SideMenuContent(
|
||||
// 顶部状态栏间距
|
||||
val statusBarHeight = WindowInsets.systemBars.asPaddingValues().calculateTopPadding()
|
||||
|
||||
// 扫一扫功能入口 - 右边距离右边66pt
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.offset(x = (-112).dp, y = 88.dp)
|
||||
.noRippleClickable {
|
||||
// 扫一扫功能:跳转到扫码页面
|
||||
coroutineScope.launch {
|
||||
onClose()
|
||||
navController.navigate(NavigationRoute.ScanQr.route)
|
||||
}
|
||||
},
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// 扫一扫图标(使用现有图标或占位)
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.sao),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(24.dp),
|
||||
colorFilter = ColorFilter.tint(iconColor)
|
||||
)
|
||||
}
|
||||
// 绝对定位的"扫一扫"文字:上方71.5dp,右侧66dp
|
||||
// 扫一扫功能入口
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.offset(x = (-60).dp, y = 88.dp)
|
||||
.noRippleClickable {
|
||||
coroutineScope.launch {
|
||||
onClose()
|
||||
navController.navigate(NavigationRoute.ScanQr.route)
|
||||
}
|
||||
},
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.sao),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(24.dp),
|
||||
colorFilter = ColorFilter.tint(iconColor)
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.scan_qr),
|
||||
fontSize = 14.sp,
|
||||
color = textColor,
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.offset(x = (-66).dp, y = 91.5.dp)
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
// QR码图标 - 右边距离右边112dp,上边距离上边68pt
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.qr_code_icon),
|
||||
|
||||
@@ -91,6 +91,10 @@ import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import com.airbnb.lottie.compose.LottieAnimation
|
||||
import com.airbnb.lottie.compose.LottieCompositionSpec
|
||||
import com.airbnb.lottie.compose.LottieConstants
|
||||
import com.airbnb.lottie.compose.rememberLottieComposition
|
||||
|
||||
// 检测是否接近列表底部的扩展函数
|
||||
fun LazyListState.isScrolledToEnd(buffer: Int = 3): Boolean {
|
||||
@@ -382,25 +386,19 @@ fun Agent() {
|
||||
}
|
||||
}
|
||||
|
||||
// 加载更多指示器(仅在展示“发现更多”时显示)
|
||||
// 加载更多指示器(仅在展示"发现更多"时显示)
|
||||
if (viewModel.isLoadingMore) {
|
||||
item {
|
||||
Row(
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 24.dp),
|
||||
horizontalArrangement = Arrangement.Center
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
androidx.compose.material3.CircularProgressIndicator(
|
||||
modifier = Modifier.size(24.dp),
|
||||
color = AppColors.text,
|
||||
strokeWidth = 2.dp
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
androidx.compose.material3.Text(
|
||||
text = "加载中...",
|
||||
color = AppColors.secondaryText,
|
||||
fontSize = 14.sp
|
||||
LottieAnimation(
|
||||
composition = rememberLottieComposition(LottieCompositionSpec.Asset("star_Loader.lottie")).value,
|
||||
iterations = LottieConstants.IterateForever,
|
||||
modifier = Modifier.size(80.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -920,26 +918,16 @@ fun ChatRoomCard(
|
||||
modifier = Modifier
|
||||
.size(120.dp)
|
||||
.background(
|
||||
color = AppColors.background,
|
||||
color = Color.Transparent,
|
||||
shape = RoundedCornerShape(12.dp)
|
||||
),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(32.dp),
|
||||
color = AppColors.main
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
androidx.compose.material3.Text(
|
||||
text = "加入中...",
|
||||
fontSize = 14.sp,
|
||||
color = AppColors.text
|
||||
)
|
||||
}
|
||||
LottieAnimation(
|
||||
composition = rememberLottieComposition(LottieCompositionSpec.Asset("star_Loader.lottie")).value,
|
||||
iterations = LottieConstants.IterateForever,
|
||||
modifier = Modifier.size(96.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,10 @@ import com.aiosman.ravenow.ui.composables.rememberDebouncer
|
||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
import com.aiosman.ravenow.utils.NetworkUtils
|
||||
import com.aiosman.ravenow.ui.network.ReloadButton
|
||||
import com.airbnb.lottie.compose.LottieAnimation
|
||||
import com.airbnb.lottie.compose.LottieCompositionSpec
|
||||
import com.airbnb.lottie.compose.LottieConstants
|
||||
import com.airbnb.lottie.compose.rememberLottieComposition
|
||||
|
||||
/**
|
||||
* 智能体聊天列表页面
|
||||
@@ -187,9 +191,10 @@ fun AgentChatListScreen() {
|
||||
.padding(16.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(24.dp),
|
||||
color = AppColors.main
|
||||
LottieAnimation(
|
||||
composition = rememberLottieComposition(LottieCompositionSpec.Asset("star_Loader.lottie")).value,
|
||||
iterations = LottieConstants.IterateForever,
|
||||
modifier = Modifier.size(80.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
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
|
||||
@@ -212,7 +214,7 @@ fun NewsCommentModal(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "${currentCommentCount}条评论",
|
||||
text = stringResource(R.string.comment_count, currentCommentCount),
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = AppColors.text
|
||||
@@ -237,24 +239,53 @@ fun NewsCommentModal(
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
) {
|
||||
LazyColumn {
|
||||
item {
|
||||
CommentContent(
|
||||
viewModel = commentViewModel,
|
||||
onLongClick = { comment ->
|
||||
showCommentMenu = true
|
||||
contextComment = comment
|
||||
},
|
||||
onReply = { parentComment, _, _, _ ->
|
||||
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.COMMENT_MOMENT)) {
|
||||
debouncedNavigation {
|
||||
navController.navigate(NavigationRoute.Login.route)
|
||||
}
|
||||
} else {
|
||||
replyComment = parentComment
|
||||
}
|
||||
}
|
||||
val isCommentListEmpty = !commentViewModel.isLoading &&
|
||||
currentCommentCount == 0 &&
|
||||
commentViewModel.commentsList.isEmpty() &&
|
||||
commentViewModel.addedCommentList.isEmpty()
|
||||
|
||||
if (isCommentListEmpty) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(bottom = 32.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.invalid_name_3),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.width(160.dp)
|
||||
.height(130.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.news_no_comments),
|
||||
fontSize = 15.sp,
|
||||
color = AppColors.text
|
||||
)
|
||||
}
|
||||
} else {
|
||||
LazyColumn {
|
||||
item {
|
||||
CommentContent(
|
||||
viewModel = commentViewModel,
|
||||
onLongClick = { comment ->
|
||||
showCommentMenu = true
|
||||
contextComment = comment
|
||||
},
|
||||
onReply = { parentComment, _, _, _ ->
|
||||
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.COMMENT_MOMENT)) {
|
||||
debouncedNavigation {
|
||||
navController.navigate(NavigationRoute.Login.route)
|
||||
}
|
||||
} else {
|
||||
replyComment = parentComment
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.pager.VerticalPager
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
@@ -401,7 +402,7 @@ fun NewsItem(
|
||||
count = "",
|
||||
isActive = false,
|
||||
text = stringResource(R.string.share),
|
||||
textSize = 8.sp
|
||||
textSize = 8.sp,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -425,7 +426,7 @@ fun NewsActionButton(
|
||||
|
||||
Row(
|
||||
modifier = modifier
|
||||
.width(60.dp)
|
||||
.defaultMinSize(minWidth = 60.dp)
|
||||
.background(
|
||||
color = AppColors.secondaryBackground,
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
@@ -449,7 +450,8 @@ fun NewsActionButton(
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(
|
||||
text = count,
|
||||
fontSize = 12.sp,
|
||||
fontSize = 8.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = AppColors.text
|
||||
)
|
||||
}
|
||||
@@ -458,7 +460,8 @@ fun NewsActionButton(
|
||||
Text(
|
||||
text = text,
|
||||
fontSize = textSize,
|
||||
color = AppColors.text
|
||||
color = AppColors.text,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,14 @@ import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.pager.VerticalPager
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Text
|
||||
import com.airbnb.lottie.compose.LottieAnimation
|
||||
import com.airbnb.lottie.compose.LottieCompositionSpec
|
||||
import com.airbnb.lottie.compose.LottieConstants
|
||||
import com.airbnb.lottie.compose.rememberLottieComposition
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -75,17 +79,11 @@ fun RecommendScreen() {
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
CircularProgressIndicator(color = AppColors.main)
|
||||
Text(
|
||||
text = "加载中...",
|
||||
modifier = Modifier.padding(top = 16.dp),
|
||||
color = AppColors.text,
|
||||
fontSize = 14.sp
|
||||
)
|
||||
}
|
||||
LottieAnimation(
|
||||
composition = rememberLottieComposition(LottieCompositionSpec.Asset("star_Loader.lottie")).value,
|
||||
iterations = LottieConstants.IterateForever,
|
||||
modifier = Modifier.size(96.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,13 @@ package com.aiosman.ravenow.ui.index.tabs.moment.tabs.shorts
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Text
|
||||
import com.airbnb.lottie.compose.LottieAnimation
|
||||
import com.airbnb.lottie.compose.LottieCompositionSpec
|
||||
import com.airbnb.lottie.compose.LottieConstants
|
||||
import com.airbnb.lottie.compose.rememberLottieComposition
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -77,19 +79,11 @@ fun ShortVideoScreen(
|
||||
.background(AppColors.background),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = androidx.compose.foundation.layout.Arrangement.Center
|
||||
) {
|
||||
CircularProgressIndicator(color = AppColors.main)
|
||||
Text(
|
||||
text = "加载中...",
|
||||
modifier = Modifier.padding(top = 16.dp),
|
||||
color = AppColors.text,
|
||||
fontSize = 14.sp
|
||||
)
|
||||
}
|
||||
LottieAnimation(
|
||||
composition = rememberLottieComposition(LottieCompositionSpec.Asset("star_Loader.lottie")).value,
|
||||
iterations = LottieConstants.IterateForever,
|
||||
modifier = Modifier.size(96.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
// 错误状态
|
||||
@@ -130,10 +124,10 @@ fun ShortVideoScreen(
|
||||
.background(AppColors.background),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = "准备加载...",
|
||||
color = AppColors.text,
|
||||
fontSize = 16.sp
|
||||
LottieAnimation(
|
||||
composition = rememberLottieComposition(LottieCompositionSpec.Asset("star_Loader.lottie")).value,
|
||||
iterations = LottieConstants.IterateForever,
|
||||
modifier = Modifier.size(80.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -683,18 +683,26 @@ fun TopNavigationBar(
|
||||
// 仅本人主页显示积分:收集全局积分
|
||||
val pointsBalanceState = if (isSelf) PointService.pointsBalance.collectAsState(initial = null) else null
|
||||
|
||||
// 响应式监听暗色模式变化 - 通过 LocalAppTheme 的变化来触发重组
|
||||
// 当 AppState.darkMode 改变时,AppState.appTheme 也会改变,从而触发 LocalAppTheme 更新
|
||||
val darkMode = AppState.darkMode
|
||||
|
||||
// 根据背景透明度和暗色模式决定图标颜色
|
||||
// 暗色模式下:图标始终为白色
|
||||
// 亮色模式下:根据背景透明度决定,透明度为1时变黑,否则为白色
|
||||
val iconColor = if (AppState.darkMode) {
|
||||
Color.White // 暗色模式下图标始终为白色
|
||||
} else {
|
||||
if (backgroundAlpha >= 1f) Color.Black else Color.White
|
||||
val iconColor = remember(darkMode, backgroundAlpha) {
|
||||
if (darkMode) {
|
||||
Color.White // 暗色模式下图标始终为白色
|
||||
} else {
|
||||
if (backgroundAlpha >= 1f) Color.Black else Color.White
|
||||
}
|
||||
}
|
||||
val cardBorderColor = if (AppState.darkMode) {
|
||||
Color.White.copy(alpha = 0.35f) // 暗色模式下使用半透明白色,避免整体变白
|
||||
} else {
|
||||
if (backgroundAlpha >= 1f) Color.Black else Color.White
|
||||
val cardBorderColor = remember(darkMode, backgroundAlpha) {
|
||||
if (darkMode) {
|
||||
Color.White.copy(alpha = 0.35f) // 暗色模式下使用半透明白色,避免整体变白
|
||||
} else {
|
||||
if (backgroundAlpha >= 1f) Color.Black else Color.White
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
@@ -709,10 +717,10 @@ fun TopNavigationBar(
|
||||
val totalHeight = statusBarHeight + navigationBarHeight
|
||||
|
||||
// 根据滚动位置计算背景颜色,从透明逐渐变为实色填充,尽快完成
|
||||
val toolbarBackgroundColor = remember(backgroundAlpha) {
|
||||
val toolbarBackgroundColor = remember(backgroundAlpha, darkMode) {
|
||||
val progress = backgroundAlpha.coerceIn(0f, 1f)
|
||||
|
||||
if (AppState.darkMode) {
|
||||
if (darkMode) {
|
||||
// 暗色模式下:从透明逐渐变为黑色实色填充
|
||||
Color.Black.copy(alpha = progress)
|
||||
} else {
|
||||
@@ -744,9 +752,9 @@ fun TopNavigationBar(
|
||||
// 左侧:互动数据卡片(仅自己的界面显示)
|
||||
if (isSelf) {
|
||||
// 根据 toolbar 背景透明度动态调整卡片背景
|
||||
val cardBackgroundColor = remember(backgroundAlpha) {
|
||||
val cardBackgroundColor = remember(backgroundAlpha, darkMode) {
|
||||
val smoothProgress = backgroundAlpha.coerceIn(0f, 1f)
|
||||
if (AppState.darkMode) {
|
||||
if (darkMode) {
|
||||
// 暗色模式:保持在半透明灰白区间,避免滚动到顶部后变纯白
|
||||
val minAlpha = 0.18f
|
||||
val maxAlpha = 0.35f
|
||||
@@ -786,7 +794,7 @@ fun TopNavigationBar(
|
||||
text = pointsBalanceState?.value?.balance?.let { numberFormat.format(it) } ?: "--",
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.W500,
|
||||
color = if (AppState.darkMode) Color.White else Color.Black, // 暗色模式下为白色,亮色模式下为黑色
|
||||
color = remember(darkMode) { if (darkMode) Color.White else Color.Black }, // 暗色模式下为白色,亮色模式下为黑色
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
@@ -839,7 +847,7 @@ fun TopNavigationBar(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// 返回按钮:深色模式下为白色,亮色模式下为黑色
|
||||
val backButtonColor = if (AppState.darkMode) Color.White else Color.Black
|
||||
val backButtonColor = remember(darkMode) { if (darkMode) Color.White else Color.Black }
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.rider_pro_back_icon),
|
||||
contentDescription = "Back",
|
||||
|
||||
@@ -25,6 +25,10 @@ import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Text
|
||||
import com.airbnb.lottie.compose.LottieAnimation
|
||||
import com.airbnb.lottie.compose.LottieCompositionSpec
|
||||
import com.airbnb.lottie.compose.LottieConstants
|
||||
import com.airbnb.lottie.compose.rememberLottieComposition
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -184,9 +188,10 @@ fun GroupChatEmptyContent(
|
||||
.padding(16.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(24.dp),
|
||||
color = AppColors.main
|
||||
LottieAnimation(
|
||||
composition = rememberLottieComposition(LottieCompositionSpec.Asset("star_Loader.lottie")).value,
|
||||
iterations = LottieConstants.IterateForever,
|
||||
modifier = Modifier.size(80.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,12 @@ import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.wrapContentWidth
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Text
|
||||
@@ -102,40 +104,21 @@ fun UserItem(
|
||||
|
||||
// 统计数据
|
||||
Row(
|
||||
modifier = Modifier.weight(1f),
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(0.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// 帖子数
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.width(80.dp)
|
||||
.height(40.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(
|
||||
text = postCount.toString(),
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 15.sp,
|
||||
color = AppColors.text,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.posts),
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 11.sp,
|
||||
color = AppColors.text,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
StatColumn(
|
||||
modifier = Modifier.weight(1f),
|
||||
value = postCount.toString(),
|
||||
label = stringResource(R.string.posts)
|
||||
)
|
||||
|
||||
// 粉丝数
|
||||
Column(
|
||||
StatColumn(
|
||||
modifier = Modifier
|
||||
.width(80.dp)
|
||||
.height(40.dp)
|
||||
.weight(1f)
|
||||
.noRippleClickable {
|
||||
followerDebouncer {
|
||||
navController.navigate(
|
||||
@@ -146,32 +129,13 @@ fun UserItem(
|
||||
)
|
||||
}
|
||||
},
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(
|
||||
text = formattedFollowerCount,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 15.sp,
|
||||
color = AppColors.text,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.followers_upper),
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 11.sp,
|
||||
color = AppColors.text,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
value = formattedFollowerCount,
|
||||
label = stringResource(R.string.followers_upper)
|
||||
)
|
||||
|
||||
// 关注数
|
||||
Column(
|
||||
StatColumn(
|
||||
modifier = Modifier
|
||||
.width(80.dp)
|
||||
.height(40.dp)
|
||||
.offset(x = 6.dp)
|
||||
.weight(1f)
|
||||
.noRippleClickable {
|
||||
followingDebouncer {
|
||||
navController.navigate(
|
||||
@@ -182,25 +146,9 @@ fun UserItem(
|
||||
)
|
||||
}
|
||||
},
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(
|
||||
text = accountProfileEntity.followingCount.toString(),
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 15.sp,
|
||||
color = AppColors.text,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.following_upper),
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 11.sp,
|
||||
color = AppColors.text,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
value = accountProfileEntity.followingCount.toString(),
|
||||
label = stringResource(R.string.following_upper)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,6 +238,38 @@ fun UserItem(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StatColumn(
|
||||
modifier: Modifier = Modifier,
|
||||
value: String,
|
||||
label: String
|
||||
) {
|
||||
val AppColors = LocalAppTheme.current
|
||||
Column(
|
||||
modifier = modifier
|
||||
.heightIn(min = 40.dp)
|
||||
.wrapContentWidth(Alignment.CenterHorizontally),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(
|
||||
text = value,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 15.sp,
|
||||
color = AppColors.text,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Text(
|
||||
text = label,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 11.sp,
|
||||
color = AppColors.text,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ProfileTag(
|
||||
text: String,
|
||||
|
||||
@@ -274,14 +274,14 @@ fun HistorySection(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "历史搜索",
|
||||
text = stringResource(R.string.recent_search),
|
||||
color = AppColors.text,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.W600
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Text(
|
||||
text = "清空",
|
||||
text = stringResource(R.string.clear),
|
||||
color = AppColors.secondaryText,
|
||||
fontSize = 14.sp,
|
||||
modifier = Modifier.noRippleClickable { onClear() }
|
||||
|
||||
@@ -18,6 +18,7 @@ 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.Divider
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
@@ -33,7 +34,6 @@ import android.graphics.BitmapFactory
|
||||
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.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
@@ -112,7 +112,7 @@ fun DraftBoxBottomSheet(
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = "暂无草稿",
|
||||
text = stringResource(R.string.no_drafts),
|
||||
fontSize = 16.sp,
|
||||
color = AppColors.secondaryText
|
||||
)
|
||||
@@ -122,7 +122,7 @@ fun DraftBoxBottomSheet(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
verticalArrangement = Arrangement.spacedBy(0.dp)
|
||||
) {
|
||||
itemsIndexed(drafts) { index, draft ->
|
||||
DraftItem(
|
||||
@@ -141,12 +141,22 @@ fun DraftBoxBottomSheet(
|
||||
AppColors = AppColors,
|
||||
context = context
|
||||
)
|
||||
// 在草稿项之间添加分割线(最后一个不添加)
|
||||
if (index < drafts.size - 1) {
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Divider(
|
||||
color = AppColors.secondaryText.copy(alpha = 0.2f),
|
||||
thickness = 0.5.dp,
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 底部提示
|
||||
Text(
|
||||
text = "仅保存最近5个草稿",
|
||||
text = stringResource(R.string.only_save_the_last_5_drafts),
|
||||
fontSize = 12.sp,
|
||||
color = AppColors.secondaryText,
|
||||
modifier = Modifier
|
||||
@@ -172,7 +182,7 @@ private fun DraftItem(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(Color.White)
|
||||
.background(AppColors.secondaryBackground)
|
||||
.padding(12.dp)
|
||||
) {
|
||||
Column {
|
||||
@@ -206,7 +216,8 @@ private fun DraftItem(
|
||||
DraftImageThumbnail(
|
||||
imageItem = imageItem,
|
||||
context = context,
|
||||
modifier = Modifier.size(55.dp)
|
||||
modifier = Modifier.size(55.dp),
|
||||
AppColors = AppColors
|
||||
)
|
||||
}
|
||||
|
||||
@@ -216,7 +227,7 @@ private fun DraftItem(
|
||||
modifier = Modifier
|
||||
.size(55.dp)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(Color(0xFFFAF9FB)),
|
||||
.background(AppColors.inputBackground),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
@@ -250,7 +261,7 @@ private fun DraftItem(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.rider_pro_moment_apply),
|
||||
painter = painterResource(id = R.mipmap.icons_infor_edit),
|
||||
contentDescription = "edit",
|
||||
modifier = Modifier.size(16.dp),
|
||||
tint = AppColors.text
|
||||
@@ -297,12 +308,13 @@ private fun DraftItem(
|
||||
private fun DraftImageThumbnail(
|
||||
imageItem: DraftImageItem,
|
||||
context: android.content.Context,
|
||||
modifier: Modifier = Modifier
|
||||
modifier: Modifier = Modifier,
|
||||
AppColors: AppThemeData
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(Color(0xFFFAF9FB))
|
||||
|
||||
) {
|
||||
val file = File(context.cacheDir, imageItem.filename)
|
||||
if (file.exists()) {
|
||||
@@ -338,7 +350,7 @@ private fun DraftImageThumbnail(
|
||||
painter = painterResource(id = R.drawable.rider_pro_new_post_add_pic),
|
||||
contentDescription = "image",
|
||||
modifier = Modifier.size(24.dp),
|
||||
tint = Color.Gray
|
||||
tint = AppColors.secondaryText
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ fun NewPostScreen() {
|
||||
e.printStackTrace()
|
||||
Toast.makeText(
|
||||
context,
|
||||
"文案优化失败:${e.message ?: "请稍后重试"}",
|
||||
"${e.message ?: "请稍后重试"}",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
} finally {
|
||||
@@ -345,16 +345,18 @@ fun NewPostScreen() {
|
||||
|
||||
// 底部背景图
|
||||
if (isRequesting) {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.component),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(400.dp)
|
||||
.align(Alignment.BottomStart)
|
||||
.offset(y = (-40).dp),
|
||||
contentScale = ContentScale.FillBounds
|
||||
)
|
||||
if (!AppState.darkMode) {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.component),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(400.dp)
|
||||
.align(Alignment.BottomStart)
|
||||
.offset(y = (-40).dp),
|
||||
contentScale = ContentScale.FillBounds
|
||||
)
|
||||
}
|
||||
|
||||
// 加载动画显示在背景图上方,按钮下方80dp区域
|
||||
Box(
|
||||
|
||||
@@ -106,6 +106,11 @@ data class Draft(
|
||||
val createdAt: Long = System.currentTimeMillis()
|
||||
)
|
||||
object NewPostViewModel : ViewModel() {
|
||||
private data class DraftSnapshot(
|
||||
val textContent: String,
|
||||
val images: List<DraftImageItem>
|
||||
)
|
||||
|
||||
var momentService: MomentService = MomentServiceImpl()
|
||||
var textContent by mutableStateOf("")
|
||||
var aiTextContent by mutableStateOf("")
|
||||
@@ -117,6 +122,7 @@ object NewPostViewModel : ViewModel() {
|
||||
var currentPhotoUri: Uri? = null
|
||||
var draft: Draft? = null
|
||||
private var draftSaved = false // 标记草稿是否已保存,避免重复保存
|
||||
private var lastLoadedDraftSnapshot: DraftSnapshot? = null
|
||||
// watch textContent change and save draft
|
||||
// fun saveDraft() {
|
||||
// draft = Draft(textContent, imageList.map {
|
||||
@@ -131,6 +137,7 @@ object NewPostViewModel : ViewModel() {
|
||||
imageList = listOf()
|
||||
relPostId = null
|
||||
draftSaved = false // 重置保存标志
|
||||
lastLoadedDraftSnapshot = null
|
||||
}
|
||||
|
||||
fun asNewPostWithImageUris(imageUris: List<String>) {
|
||||
@@ -214,13 +221,24 @@ object NewPostViewModel : ViewModel() {
|
||||
return
|
||||
}
|
||||
|
||||
val currentSnapshot = DraftSnapshot(
|
||||
textContent = textContent,
|
||||
images = imageList.map { DraftImageItem.fromImageItem(it) }
|
||||
)
|
||||
|
||||
if (lastLoadedDraftSnapshot == currentSnapshot) {
|
||||
draftSaved = true
|
||||
return
|
||||
}
|
||||
|
||||
val draftStore = DraftStore(context)
|
||||
val draft = Draft(
|
||||
textContent = textContent,
|
||||
imageList = imageList.map { DraftImageItem.fromImageItem(it) }
|
||||
textContent = currentSnapshot.textContent,
|
||||
imageList = currentSnapshot.images
|
||||
)
|
||||
draftStore.saveDraft(draft)
|
||||
draftSaved = true // 标记已保存
|
||||
lastLoadedDraftSnapshot = currentSnapshot
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,6 +248,10 @@ object NewPostViewModel : ViewModel() {
|
||||
textContent = draft.textContent
|
||||
aiTextContent = ""
|
||||
draftSaved = false // 加载草稿后重置保存标志,允许重新保存
|
||||
lastLoadedDraftSnapshot = DraftSnapshot(
|
||||
textContent = draft.textContent,
|
||||
images = draft.imageList
|
||||
)
|
||||
|
||||
// 从草稿的图片URI恢复图片列表
|
||||
imageList = withContext(Dispatchers.IO) {
|
||||
|
||||
BIN
app/src/main/res/mipmap-hdpi/baiyang.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
app/src/main/res/mipmap-hdpi/chunv.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
app/src/main/res/mipmap-hdpi/jingniu.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
app/src/main/res/mipmap-hdpi/juxie.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/mipmap-hdpi/moxie.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
app/src/main/res/mipmap-hdpi/sheshou.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
app/src/main/res/mipmap-hdpi/shizi.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
app/src/main/res/mipmap-hdpi/shuangyu.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
app/src/main/res/mipmap-hdpi/shuangzi.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
app/src/main/res/mipmap-hdpi/shuiping.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
app/src/main/res/mipmap-hdpi/tiancheng.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
app/src/main/res/mipmap-hdpi/tianxie.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
app/src/main/res/mipmap-mdpi/baiyang.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
app/src/main/res/mipmap-mdpi/chunv.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/mipmap-mdpi/jingniu.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/mipmap-mdpi/juxie.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
app/src/main/res/mipmap-mdpi/moxie.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/mipmap-mdpi/sheshou.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
app/src/main/res/mipmap-mdpi/shizi.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/mipmap-mdpi/shuangyu.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
app/src/main/res/mipmap-mdpi/shuangzi.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/main/res/mipmap-mdpi/shuiping.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/mipmap-mdpi/tiancheng.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/main/res/mipmap-mdpi/tianxie.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
app/src/main/res/mipmap-xhdpi/baiyang.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/mipmap-xhdpi/chunv.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
app/src/main/res/mipmap-xhdpi/jingniu.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
app/src/main/res/mipmap-xhdpi/juxie.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
app/src/main/res/mipmap-xhdpi/moxie.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
app/src/main/res/mipmap-xhdpi/sheshou.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
app/src/main/res/mipmap-xhdpi/shizi.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/mipmap-xhdpi/shuangyu.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/mipmap-xhdpi/shuangzi.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
app/src/main/res/mipmap-xhdpi/shuiping.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
app/src/main/res/mipmap-xhdpi/tiancheng.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
app/src/main/res/mipmap-xhdpi/tianxie.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/baiyang.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/chunv.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/jingniu.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/juxie.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/moxie.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/sheshou.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/shizi.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/shuangyu.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/shuangzi.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/shuiping.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/tiancheng.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/tianxie.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/baiyang.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/chunv.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/jingniu.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/juxie.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/moxie.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/sheshou.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/shizi.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/shuangyu.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/shuangzi.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/shuiping.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/tiancheng.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/tianxie.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
@@ -210,7 +210,16 @@
|
||||
<string name="text_error_password_too_long">パスワードは%1$d文字を超えることはできません</string>
|
||||
<string name="block">ブロック</string>
|
||||
<string name="read_full_article">全文を読む</string>
|
||||
<string name="news_no_comments">まだ誰もノックしてないよ</string>
|
||||
<string name="drafts">ドラフトボックス</string>
|
||||
<string name="no_drafts">草稿はしばらくありません</string>
|
||||
<string name="only_save_the_last_5_drafts">最後の5つのドラフトのみ保存</string>
|
||||
<string name="memory_paid">支払い済み:</string>
|
||||
<string name="memory_used">使用済み:</string>
|
||||
<string name="upper_limit">利用可能上限:</string>
|
||||
<string name="no_memory">記憶がありません</string>
|
||||
<string name="add_memory">上部のボタンをクリックしてグループ記憶を追加してください</string>
|
||||
<string name="recent_search">けんさくりれき</string>
|
||||
|
||||
<!-- Create Bottom Sheet -->
|
||||
<string name="create_title">作成</string>
|
||||
@@ -274,6 +283,7 @@
|
||||
<string name="group_chat_info_memory_description">AIは記憶に基づいてグループチャットであなたをより理解します</string>
|
||||
<string name="group_chat_info_add_memory">メモリを追加</string>
|
||||
<string name="group_chat_info_memory_manage">メモリ管理</string>
|
||||
<string name="group_chat_info_memory_manage2">メモリ管理</string>
|
||||
<string name="group_chat_info_group_settings">グループ設定</string>
|
||||
<string name="group_chat_info_group_visibility">グループの可視性</string>
|
||||
<string name="group_chat_info_locked">ロック中</string>
|
||||
|
||||
@@ -70,7 +70,11 @@
|
||||
<string name="new_password_tip1">请输入新密码</string>
|
||||
<string name="confirm_new_password">确认新密码</string>
|
||||
<string name="confirm_new_password_tip1">请确认新密码</string>
|
||||
|
||||
<string name="memory_paid">已付费:</string>
|
||||
<string name="memory_used">已使用:</string>
|
||||
<string name="upper_limit">可用上限:</string>
|
||||
<string name="no_memory">暂无记忆</string>
|
||||
<string name="add_memory">点击上方按钮添加群记忆</string>
|
||||
|
||||
<string name="cancel">取消</string>
|
||||
<string name="bio">个性签名</string>
|
||||
@@ -213,7 +217,11 @@
|
||||
<string name="chatting_now">人正在热聊…</string>
|
||||
<string name="block">拉黑</string>
|
||||
<string name="read_full_article">查看全文</string>
|
||||
<string name="news_no_comments">还没有人敲门</string>
|
||||
<string name="drafts">草稿箱</string>
|
||||
<string name="no_drafts">暂无草稿</string>
|
||||
<string name="only_save_the_last_5_drafts">仅保存最近5个草稿</string>
|
||||
<string name="recent_search">历史搜索</string>
|
||||
|
||||
<!-- Create Bottom Sheet -->
|
||||
<string name="create_title">创建</string>
|
||||
@@ -277,6 +285,7 @@
|
||||
<string name="group_chat_info_memory_description">AI 会根据记忆在群聊里更懂你</string>
|
||||
<string name="group_chat_info_add_memory">添加记忆</string>
|
||||
<string name="group_chat_info_memory_manage">记忆管理</string>
|
||||
<string name="group_chat_info_memory_manage2">记忆管理</string>
|
||||
<string name="group_chat_info_group_settings">群资料设置</string>
|
||||
<string name="group_chat_info_group_visibility">群可见性</string>
|
||||
<string name="group_chat_info_locked">待解锁</string>
|
||||
@@ -367,21 +376,6 @@
|
||||
<string name="complete_tasks_desc">完成任务可获得奖励</string>
|
||||
<string name="recharge_pai_coin">充值派币</string>
|
||||
<string name="recharge_pai_coin_desc">多种套餐可选,立即充值</string>
|
||||
|
||||
<!-- Transaction History Reasons -->
|
||||
<string name="earn_register">新用户注册奖励</string>
|
||||
<string name="earn_daily">每日签到奖励</string>
|
||||
<string name="earn_task">任务完成奖励</string>
|
||||
<string name="earn_invite">邀请好友奖励</string>
|
||||
<string name="earn_recharge">充值获得</string>
|
||||
<string name="spend_group_create">创建群聊</string>
|
||||
<string name="spend_group_expand">扩容群聊</string>
|
||||
<string name="spend_agent_private">Agent 私密模式</string>
|
||||
<string name="spend_agent_memory">Agent 记忆添加</string>
|
||||
<string name="spend_room_memory">房间记忆添加</string>
|
||||
<string name="spend_chat_background">自定义聊天背景</string>
|
||||
<string name="spend_schedule_event">定时事件解锁</string>
|
||||
|
||||
<string name="create_group_chat_failed">创建群聊失败: %1$s</string>
|
||||
<string name="create_group_chat_confirm_title">创建群聊确认</string>
|
||||
<string name="create_group_chat_required_cost">需要消耗:</string>
|
||||
@@ -401,6 +395,20 @@
|
||||
<string name="explore">去探索</string>
|
||||
<string name="reply_to_user">回复@%1$s</string>
|
||||
<string name="error_select_at_least_one_image">请至少选择一张图片</string>
|
||||
|
||||
<!-- Transaction History Reasons -->
|
||||
<string name="earn_register">新用户注册奖励</string>
|
||||
<string name="earn_daily">每日签到奖励</string>
|
||||
<string name="earn_task">任务完成奖励</string>
|
||||
<string name="earn_invite">好友邀请奖励</string>
|
||||
<string name="earn_recharge">充值</string>
|
||||
<string name="spend_group_create">群聊创建</string>
|
||||
<string name="spend_group_expand">群聊扩展</string>
|
||||
<string name="spend_agent_private">智能体私密模式</string>
|
||||
<string name="spend_agent_memory">智能体记忆添加</string>
|
||||
<string name="spend_room_memory">房间记忆添加</string>
|
||||
<string name="spend_chat_background">自定义聊天背景</string>
|
||||
<string name="spend_schedule_event">日程事件解锁</string>
|
||||
<string name="awaiting_traveler">等一位旅人~</string>
|
||||
<string name="no_one_pinged_yet">还没有人来打扰你</string>
|
||||
<string name="cosmos_awaits">小宇宙等你探索。</string>
|
||||
|
||||
@@ -209,7 +209,16 @@
|
||||
<string name="text_error_password_too_long">Password cannot exceed %1$d characters</string>
|
||||
<string name="block">Block</string>
|
||||
<string name="read_full_article">Read full article</string>
|
||||
<string name="news_no_comments">No one’s knocked yet</string>
|
||||
<string name="drafts">drafts</string>
|
||||
<string name="no_drafts">No draft</string>
|
||||
<string name="only_save_the_last_5_drafts">Only save the last 5 drafts</string>
|
||||
<string name="memory_paid">Paid:</string>
|
||||
<string name="memory_used">Used:</string>
|
||||
<string name="upper_limit">Available Limit:</string>
|
||||
<string name="no_memory">No memory yet</string>
|
||||
<string name="add_memory">Click the button above to add group memory</string>
|
||||
<string name="recent_search">Recent Search</string>
|
||||
|
||||
<!-- Create Bottom Sheet -->
|
||||
<string name="create_title">Create</string>
|
||||
@@ -273,6 +282,7 @@
|
||||
<string name="group_chat_info_memory_description">AI will understand you better in group chat based on memory</string>
|
||||
<string name="group_chat_info_add_memory">Add Memory</string>
|
||||
<string name="group_chat_info_memory_manage">Memory Management</string>
|
||||
<string name="group_chat_info_memory_manage2">Memory</string>
|
||||
<string name="group_chat_info_group_settings">Group Settings</string>
|
||||
<string name="group_chat_info_group_visibility">Group Visibility</string>
|
||||
<string name="group_chat_info_locked">Locked</string>
|
||||
@@ -361,21 +371,6 @@
|
||||
<string name="complete_tasks_desc">Complete tasks to earn rewards</string>
|
||||
<string name="recharge_pai_coin">Recharge Pai Coin</string>
|
||||
<string name="recharge_pai_coin_desc">Multiple packages available, recharge now</string>
|
||||
|
||||
<!-- Transaction History Reasons -->
|
||||
<string name="earn_register">New User Registration Reward</string>
|
||||
<string name="earn_daily">Daily Check-in Reward</string>
|
||||
<string name="earn_task">Task Completion Reward</string>
|
||||
<string name="earn_invite">Invite Friends Reward</string>
|
||||
<string name="earn_recharge">Recharge</string>
|
||||
<string name="spend_group_create">Create Group Chat</string>
|
||||
<string name="spend_group_expand">Expand Group Chat</string>
|
||||
<string name="spend_agent_private">Agent Private Mode</string>
|
||||
<string name="spend_agent_memory">Agent Memory Added</string>
|
||||
<string name="spend_room_memory">Room Memory Added</string>
|
||||
<string name="spend_chat_background">Custom Chat Background</string>
|
||||
<string name="spend_schedule_event">Scheduled Event Unlocked</string>
|
||||
|
||||
<string name="create_group_chat_failed">Failed to create group chat: %1$s</string>
|
||||
<string name="create_group_chat_confirm_title">Create Group Chat</string>
|
||||
<string name="create_group_chat_required_cost">Required consumption:</string>
|
||||
@@ -395,6 +390,20 @@
|
||||
<string name="explore">Explore</string>
|
||||
<string name="reply_to_user">Reply @%1$s</string>
|
||||
<string name="error_select_at_least_one_image">Please select at least one image</string>
|
||||
|
||||
<!-- Transaction History Reasons -->
|
||||
<string name="earn_register">New User Registration Reward</string>
|
||||
<string name="earn_daily">Daily Check-in Reward</string>
|
||||
<string name="earn_task">Task Completion Reward</string>
|
||||
<string name="earn_invite">Friend Invitation Reward</string>
|
||||
<string name="earn_recharge">Recharge</string>
|
||||
<string name="spend_group_create">Group Chat Creation</string>
|
||||
<string name="spend_group_expand">Group Chat Expansion</string>
|
||||
<string name="spend_agent_private">Agent Private Mode</string>
|
||||
<string name="spend_agent_memory">Agent Memory Addition</string>
|
||||
<string name="spend_room_memory">Room Memory Addition</string>
|
||||
<string name="spend_chat_background">Custom Chat Background</string>
|
||||
<string name="spend_schedule_event">Schedule Event Unlock</string>
|
||||
<string name="awaiting_traveler">Awaiting a traveler</string>
|
||||
<string name="no_one_pinged_yet">No one has pinged you yet</string>
|
||||
<string name="cosmos_awaits">Your cosmos awaits.</string>
|
||||
|
||||