diff --git a/app/src/main/java/com/aiosman/ravenow/ui/composables/EditCommentBottomModal.kt b/app/src/main/java/com/aiosman/ravenow/ui/composables/EditCommentBottomModal.kt index a00dc72..86ec076 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/composables/EditCommentBottomModal.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/composables/EditCommentBottomModal.kt @@ -37,6 +37,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight @@ -110,7 +111,11 @@ fun EditCommentBottomModal( innerTextField() if (text.isEmpty()) { Text( - text = if (replyComment == null) "快来互动吧..." else "回复@${replyComment.name}", + text = if (replyComment == null) { + stringResource(R.string.post_comment_hint) + } else { + stringResource(R.string.reply_to_user, replyComment.name ?: "") + }, color = AppColors.text.copy(alpha = 0.3f), // 30%透明度 ) } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/composables/Moment.kt b/app/src/main/java/com/aiosman/ravenow/ui/composables/Moment.kt index a62af99..dd4742a 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/composables/Moment.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/composables/Moment.kt @@ -111,6 +111,7 @@ fun MomentCard( ) { MomentContentGroup( momentEntity = momentEntity, + imageIndex = imageIndex, onPageChange = { index -> imageIndex = index } ) } @@ -120,7 +121,6 @@ fun MomentCard( onLikeClick = onLikeClick, onAddComment = onAddComment, onFavoriteClick = onFavoriteClick, - imageIndex = imageIndex, onCommentClick = { navController.navigateToPost( momentEntity.id, @@ -327,6 +327,11 @@ fun PostImageView( images: List, onPageChange: (Int) -> Unit = {} ) { + // 如果图片列表为空,不渲染任何内容 + if (images.isEmpty()) { + return + } + val pagerState = rememberPagerState(pageCount = { images.size }) LaunchedEffect(pagerState.currentPage) { onPageChange(pagerState.currentPage) @@ -361,22 +366,83 @@ fun PostImageView( @Composable fun MomentContentGroup( momentEntity: MomentEntity, + imageIndex: Int = 0, onPageChange: (Int) -> Unit = {} ) { val AppColors = LocalAppTheme.current + val context = LocalContext.current + if (momentEntity.relMoment != null) { RelPostCard( momentEntity = momentEntity.relMoment!!, modifier = Modifier.background(Color(0xFFF8F8F8)) ) } else { - Box( + Column( modifier = Modifier.fillMaxWidth() ) { - PostImageView( - images = momentEntity.images, - onPageChange = onPageChange - ) + Box( + modifier = Modifier.fillMaxWidth() + ) { + // 优先显示图片,如果没有图片则显示视频缩略图 + if (momentEntity.images.isNotEmpty()) { + PostImageView( + images = momentEntity.images, + onPageChange = onPageChange + ) + } else if (momentEntity.videos != null && momentEntity.videos.isNotEmpty()) { + // 显示视频缩略图 + val firstVideo = momentEntity.videos.first() + val thumbnailUrl = firstVideo.thumbnailUrl ?: firstVideo.thumbnailDirectUrl + if (thumbnailUrl != null) { + Box( + modifier = Modifier + .fillMaxWidth() + .aspectRatio( + if (firstVideo.width != null && firstVideo.height != null && firstVideo.height > 0) { + firstVideo.width.toFloat() / firstVideo.height.toFloat() + } else { + 1f + } + ) + ) { + CustomAsyncImage( + context = context, + imageUrl = thumbnailUrl, + contentDescription = "Video thumbnail", + contentScale = ContentScale.Crop, + modifier = Modifier.fillMaxSize() + ) + } + } + } + } + + // 图片指示器:显示在图片下方、文案上方 + if (momentEntity.images.size > 1) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + momentEntity.images.forEachIndexed { index, _ -> + Box( + modifier = Modifier + .size(4.dp) + .clip(CircleShape) + .background( + if (imageIndex == index) Color.Red else Color.Gray.copy( + alpha = 0.5f + ) + ) + .padding(1.dp) + ) + Spacer(modifier = Modifier.width(8.dp)) + } + } + } } } if (momentEntity.momentTextContent.isNotEmpty()) { @@ -437,8 +503,7 @@ fun MomentBottomOperateRowGroup( onAddComment: () -> Unit = {}, onCommentClick: () -> Unit = {}, onFavoriteClick: () -> Unit = {}, - momentEntity: MomentEntity, - imageIndex: Int = 0 + momentEntity: MomentEntity ) { val lastClickTime = remember { mutableStateOf(0L) } val clickDelay = 500L @@ -475,93 +540,65 @@ fun MomentBottomOperateRowGroup( modifier = Modifier .fillMaxWidth() .height(56.dp) - .padding(start = 16.dp, end = 0.dp) + .padding(start = 16.dp, end = 16.dp) ) { - Column( - modifier = Modifier.fillMaxSize() + Row( + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight(), + verticalAlignment = Alignment.CenterVertically ) { - if (momentEntity.images.size > 1) { - Row( - modifier = Modifier - .fillMaxWidth() - .weight(1f), - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically - ) { - momentEntity.images.forEachIndexed { index, _ -> - Box( - modifier = Modifier - .size(4.dp) - .clip(CircleShape) - .background( - if (imageIndex == index) Color.Red else Color.Gray.copy( - alpha = 0.5f - ) - ) - .padding(1.dp) - ) - Spacer(modifier = Modifier.width(8.dp)) + Row( + modifier = Modifier.weight(1f).fillMaxHeight(), + verticalAlignment = Alignment.CenterVertically + ) { + // 点赞按钮 + MomentOperateBtn(count = momentEntity.likeCount.toString()) { + AnimatedLikeIcon( + modifier = Modifier.size(24.dp), + liked = momentEntity.liked + ) { + onLikeClick() } } + Spacer(modifier = Modifier.width(16.dp)) + // 评论按钮 + Box( + modifier = Modifier.noRippleClickable { + val currentTime = System.currentTimeMillis() + if (currentTime - lastClickTime.value > clickDelay) { + lastClickTime.value = currentTime + onCommentClick() + } + } + ) { + MomentOperateBtn( + icon = R.mipmap.icon_comment, + count = momentEntity.commentCount.toString() + ) + } + Spacer(modifier = Modifier.width(16.dp)) + // 转发按钮 + Box( + modifier = Modifier.noRippleClickable { + // TODO: 实现转发功能 + } + ) { + MomentOperateBtn( + icon = R.mipmap.icon_share, + count = "" + ) + } } - Row( - modifier = Modifier - .fillMaxWidth() - .weight(1f), - verticalAlignment = Alignment.CenterVertically - ) { - Row( - modifier = Modifier.weight(1f).fillMaxHeight(), - verticalAlignment = Alignment.CenterVertically + Spacer(modifier = Modifier.width(16.dp)) + // 收藏按钮 + MomentOperateBtn(count = momentEntity.favoriteCount.toString()) { + AnimatedFavouriteIcon( + modifier = Modifier.size(24.dp), + isFavourite = momentEntity.isFavorite ) { - // 点赞按钮 - MomentOperateBtn(count = momentEntity.likeCount.toString()) { - AnimatedLikeIcon( - modifier = Modifier.size(24.dp), - liked = momentEntity.liked - ) { - onLikeClick() - } - } - Spacer(modifier = Modifier.width(10.dp)) - // 评论按钮 - Box( - modifier = Modifier.noRippleClickable { - val currentTime = System.currentTimeMillis() - if (currentTime - lastClickTime.value > clickDelay) { - lastClickTime.value = currentTime - onCommentClick() - } - } - ) { - MomentOperateBtn( - icon = R.mipmap.icon_comment, - count = momentEntity.commentCount.toString() - ) - } - Spacer(modifier = Modifier.width(28.dp)) - // 转发按钮 - Box( - modifier = Modifier.noRippleClickable { - // TODO: 实现转发功能 - } - ) { - MomentOperateBtn( - icon = R.mipmap.icon_share, - count = "" - ) - } - } - - // 收藏按钮 - MomentOperateBtn(count = momentEntity.favoriteCount.toString()) { - AnimatedFavouriteIcon( - modifier = Modifier.size(24.dp), - isFavourite = momentEntity.isFavorite - ) { - onFavoriteClick() - } + onFavoriteClick() } } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/composables/TabItem.kt b/app/src/main/java/com/aiosman/ravenow/ui/composables/TabItem.kt index abac32b..4c9ea55 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/composables/TabItem.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/composables/TabItem.kt @@ -11,6 +11,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.wrapContentWidth import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -39,6 +40,7 @@ fun TabItem( Column( modifier = modifier + .wrapContentWidth() .noRippleClickable { onClick() }, verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally diff --git a/app/src/main/java/com/aiosman/ravenow/ui/group/CreateGroupChatScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/group/CreateGroupChatScreen.kt index 60e99af..613f731 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/group/CreateGroupChatScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/group/CreateGroupChatScreen.kt @@ -467,7 +467,7 @@ fun CreateGroupChatScreen() { ) { if (CreateGroupChatViewModel.isLoading) { Text( - text = "创建中...", + text = stringResource(R.string.agent_createing), fontSize = 16.sp, fontWeight = FontWeight.W600 ) diff --git a/app/src/main/java/com/aiosman/ravenow/ui/group/CreateGroupChatViewModel.kt b/app/src/main/java/com/aiosman/ravenow/ui/group/CreateGroupChatViewModel.kt index 0fbfc28..dd7d53d 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/group/CreateGroupChatViewModel.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/group/CreateGroupChatViewModel.kt @@ -18,6 +18,7 @@ import com.aiosman.ravenow.data.AccountService import com.aiosman.ravenow.data.AccountServiceImpl import com.aiosman.ravenow.data.UserService import com.aiosman.ravenow.data.UserServiceImpl +import com.aiosman.ravenow.R import com.aiosman.ravenow.entity.CommentEntity import com.aiosman.ravenow.exp.formatChatTime import com.aiosman.ravenow.ui.NavigationRoute @@ -55,13 +56,13 @@ object CreateGroupChatViewModel : ViewModel() { true } else { isLoading = false - val errorMsg = "创建群聊失败: ${response.message()}" + val errorMsg = context.getString(R.string.create_group_chat_failed, response.message() ?: "") showToast(errorMsg) false } } catch (e: Exception) { isLoading = false - val errorMsg = "创建群聊失败: ${e.message}" + val errorMsg = context.getString(R.string.create_group_chat_failed, e.message ?: "") showToast(errorMsg) false } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/timeline/Moment.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/timeline/Moment.kt index 873a44e..d129b0b 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/timeline/Moment.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/timeline/Moment.kt @@ -34,6 +34,8 @@ import androidx.compose.ui.graphics.Color 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 androidx.paging.compose.collectAsLazyPagingItems @@ -141,17 +143,25 @@ fun TimelineMomentsList() { ) Spacer(modifier = Modifier.size(24.dp)) Text( - text = "连接世界,从关注开始", + text = stringResource(R.string.connect_world_start_following), color = AppColors.text, fontSize = 16.sp, - fontWeight = FontWeight.W600 + fontWeight = FontWeight.W600, + textAlign = TextAlign.Center, + modifier = Modifier.padding(horizontal = 24.dp), + maxLines = 2, + overflow = TextOverflow.Ellipsis ) Spacer(modifier = Modifier.size(8.dp)) Text( - text = "不如从一个 Agent 开始认识这世界?", + text = stringResource(R.string.why_not_start_with_agent), color = AppColors.text, fontSize = 16.sp, - fontWeight = FontWeight.W400 + fontWeight = FontWeight.W400, + textAlign = TextAlign.Center, + modifier = Modifier.padding(horizontal = 24.dp), + maxLines = 2, + overflow = TextOverflow.Ellipsis ) Spacer(modifier = Modifier.size(16.dp)) ExploreButton( @@ -260,7 +270,7 @@ fun ExploreButton( contentAlignment = Alignment.Center ) { Text( - text = "去探索", + text = stringResource(R.string.explore), fontSize = 16.sp, fontWeight = FontWeight.Bold, color = Color.White diff --git a/app/src/main/java/com/aiosman/ravenow/ui/points/PointsBottomSheet.kt b/app/src/main/java/com/aiosman/ravenow/ui/points/PointsBottomSheet.kt index 2611457..d3788f1 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/points/PointsBottomSheet.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/points/PointsBottomSheet.kt @@ -35,6 +35,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color 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 @@ -82,7 +83,7 @@ fun PointsBottomSheet( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { - Text(text = "My Pai Coin", color = AppColors.text, fontSize = 20.sp, fontWeight = FontWeight.Bold) + Text(text = stringResource(R.string.my_pai_coin), color = AppColors.text, fontSize = 20.sp, fontWeight = FontWeight.Bold) Box( modifier = Modifier .clip(RoundedCornerShape(16.dp)) @@ -90,7 +91,7 @@ fun PointsBottomSheet( .clickable { onRecharge() } .padding(horizontal = 12.dp, vertical = 6.dp) ) { - Text(text = "Recharge", color = Color(0xFF6B46C1), fontSize = 14.sp, fontWeight = FontWeight.W600, + Text(text = stringResource(R.string.recharge), color = Color(0xFF6B46C1), fontSize = 14.sp, fontWeight = FontWeight.W600, modifier = Modifier .clip(RoundedCornerShape(16.dp)) .padding(0.dp) @@ -108,7 +109,7 @@ fun PointsBottomSheet( .background(AppColors.nonActive) .padding(16.dp) ) { - Text("Current Balance", color = AppColors.secondaryText, fontSize = 14.sp) + Text(stringResource(R.string.current_balance), color = AppColors.secondaryText, fontSize = 14.sp) Spacer(Modifier.height(8.dp)) Row(verticalAlignment = Alignment.CenterVertically) { Image( @@ -133,7 +134,7 @@ fun PointsBottomSheet( ) { Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.weight(1f)) { Text(text = numberFormat.format(balanceState.value?.totalEarned ?: 0), color = AppColors.text, fontSize = 18.sp, fontWeight = FontWeight.W700) - Text(text = "Total Earned", color = AppColors.secondaryText, fontSize = 12.sp) + Text(text = stringResource(R.string.total_earned), color = AppColors.secondaryText, fontSize = 12.sp) } Box( modifier = Modifier @@ -143,7 +144,7 @@ fun PointsBottomSheet( ) Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.weight(1f)) { Text(text = numberFormat.format(balanceState.value?.totalSpent ?: 0), color = AppColors.text, fontSize = 18.sp, fontWeight = FontWeight.W700) - Text(text = "Total Spent", color = AppColors.secondaryText, fontSize = 12.sp) + Text(text = stringResource(R.string.total_spent), color = AppColors.secondaryText, fontSize = 12.sp) } } } @@ -159,17 +160,15 @@ fun PointsBottomSheet( verticalAlignment = Alignment.CenterVertically ) { TabItem( - text = "Transaction History", + text = stringResource(R.string.transaction_history), isSelected = tab == 0, - onClick = { tab = 0 }, - modifier = Modifier.weight(1f) + onClick = { tab = 0 } ) TabSpacer() TabItem( - text = "How to Earn", + text = stringResource(R.string.how_to_earn), isSelected = tab == 1, - onClick = { tab = 1 }, - modifier = Modifier.weight(1f) + onClick = { tab = 1 } ) } @@ -251,7 +250,7 @@ private fun PointsHistoryList( Button(onClick = onLoadMore, modifier = Modifier .fillMaxWidth() .padding(top = 8.dp)) { - Text("Load More") + Text(stringResource(R.string.load_more)) } } } @@ -290,11 +289,11 @@ private fun HowToEarnList() { } Column { - RowItem("New User Reward", "Register and get 500 Pai Coin", "+500") - RowItem("Daily Check-in", "Check in daily to earn Pai Coin", "+10-50") - RowItem("Invite Friends", "Earn Pai Coin for each friend invited", "+100") - RowItem("Complete Tasks", "Complete tasks to earn rewards", "+20-200") - RowItem("Recharge Pai Coin", "Multiple packages available, recharge now", ">") + RowItem(stringResource(R.string.new_user_reward), stringResource(R.string.new_user_reward_desc), "+500") + RowItem(stringResource(R.string.daily_check_in), stringResource(R.string.daily_check_in_desc), "+10-50") + RowItem(stringResource(R.string.invite_friends), stringResource(R.string.invite_friends_desc), "+100") + RowItem(stringResource(R.string.complete_tasks), stringResource(R.string.complete_tasks_desc), "+20-200") + RowItem(stringResource(R.string.recharge_pai_coin), stringResource(R.string.recharge_pai_coin_desc), ">") } } diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 1116912..1171734 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -323,5 +323,30 @@ ログアウト ブロックされたユーザー パスワードを確認 + + + 取引履歴 + 獲得方法 + 合計獲得 + 合計支出 + マイパイコイン + チャージ + 現在の残高 + さらに読み込む + 新規ユーザー報酬 + 登録して500パイコインを獲得 + デイリーチェックイン + 毎日チェックインしてパイコインを獲得 + 友達を招待 + 友達を招待するたびにパイコインを獲得 + タスクを完了 + タスクを完了して報酬を獲得 + パイコインをチャージ + 複数のパッケージが利用可能、今すぐチャージ + グループチャットの作成に失敗しました: %1$s + 世界をつなぐ、フォローから始めましょう + エージェントから世界を知り始めませんか? + 探検する + 返信@%1$s diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index f536b55..209b4b2 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -347,9 +347,29 @@ 被屏蔽的用户 确认密码 - MBTI - 星座、 - 保存 - 选择 MBTI - 选择 Zodiac + + + 交易历史 + 如何赚取 + 总获得 + 总支出 + 我的派币 + 充值 + 当前余额 + 加载更多 + 新用户奖励 + 注册即可获得500派币 + 每日签到 + 每日签到可获得派币 + 邀请好友 + 每邀请一位好友可获得派币 + 完成任务 + 完成任务可获得奖励 + 充值派币 + 多种套餐可选,立即充值 + 创建群聊失败: %1$s + 连接世界,从关注开始 + 不如从一个 Agent 开始认识这世界? + 去探索 + 回复@%1$s \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 35affe3..0baef6d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -340,4 +340,29 @@ Logout Blocked Users Confirm password + + + Transaction History + How to Earn + Total Earned + Total Spent + My Pai Coin + Recharge + Current Balance + Load More + New User Reward + Register and get 500 Pai Coin + Daily Check-in + Check in daily to earn Pai Coin + Invite Friends + Earn Pai Coin for each friend invited + Complete Tasks + Complete tasks to earn rewards + Recharge Pai Coin + Multiple packages available, recharge now + Failed to create group chat: %1$s + Connect the world, start by following + Why not start exploring the world with an Agent? + Explore + Reply @%1$s \ No newline at end of file