@@ -1,6 +1,8 @@
|
||||
package com.aiosman.ravenow.data
|
||||
|
||||
import android.content.Context
|
||||
import com.aiosman.ravenow.AppStore
|
||||
import com.aiosman.ravenow.R
|
||||
import com.aiosman.ravenow.data.api.ApiClient
|
||||
import com.aiosman.ravenow.data.api.DictItem
|
||||
import com.aiosman.ravenow.data.api.PointsBalance
|
||||
@@ -370,27 +372,29 @@ object PointService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取变更原因的中文描述
|
||||
* 获取变更原因的描述(支持多语言)
|
||||
*
|
||||
* @param context Context 用于获取资源
|
||||
* @param reason 变更原因代码
|
||||
* @return 中文描述
|
||||
* @return 本地化描述
|
||||
*/
|
||||
fun getReasonDescription(reason: String): String {
|
||||
return when (reason) {
|
||||
ChangeReason.EARN_REGISTER -> "新用户注册奖励"
|
||||
ChangeReason.EARN_DAILY -> "每日签到奖励"
|
||||
ChangeReason.EARN_TASK -> "任务完成奖励"
|
||||
ChangeReason.EARN_INVITE -> "邀请好友奖励"
|
||||
ChangeReason.EARN_RECHARGE -> "充值获得"
|
||||
ChangeReason.SPEND_GROUP_CREATE -> "创建群聊"
|
||||
ChangeReason.SPEND_GROUP_EXPAND -> "扩容群聊"
|
||||
ChangeReason.SPEND_AGENT_PRIVATE -> "Agent 私密模式"
|
||||
ChangeReason.SPEND_AGENT_MEMORY -> "Agent 记忆添加"
|
||||
ChangeReason.SPEND_ROOM_MEMORY -> "房间记忆添加"
|
||||
ChangeReason.SPEND_CHAT_BACKGROUND -> "自定义聊天背景"
|
||||
ChangeReason.SPEND_SCHEDULE_EVENT -> "定时事件解锁"
|
||||
else -> reason // 未知原因,返回原始代码
|
||||
fun getReasonDescription(context: Context, reason: String): String {
|
||||
val resourceId = when (reason) {
|
||||
ChangeReason.EARN_REGISTER -> R.string.earn_register
|
||||
ChangeReason.EARN_DAILY -> R.string.earn_daily
|
||||
ChangeReason.EARN_TASK -> R.string.earn_task
|
||||
ChangeReason.EARN_INVITE -> R.string.earn_invite
|
||||
ChangeReason.EARN_RECHARGE -> R.string.earn_recharge
|
||||
ChangeReason.SPEND_GROUP_CREATE -> R.string.spend_group_create
|
||||
ChangeReason.SPEND_GROUP_EXPAND -> R.string.spend_group_expand
|
||||
ChangeReason.SPEND_AGENT_PRIVATE -> R.string.spend_agent_private
|
||||
ChangeReason.SPEND_AGENT_MEMORY -> R.string.spend_agent_memory
|
||||
ChangeReason.SPEND_ROOM_MEMORY -> R.string.spend_room_memory
|
||||
ChangeReason.SPEND_CHAT_BACKGROUND -> R.string.spend_chat_background
|
||||
ChangeReason.SPEND_SCHEDULE_EVENT -> R.string.spend_schedule_event
|
||||
else -> null
|
||||
}
|
||||
return resourceId?.let { context.getString(it) } ?: reason // 未知原因,返回原始代码
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,12 @@ object AccountEditViewModel : ViewModel() {
|
||||
// 本地扩展字段
|
||||
var mbti by mutableStateOf<String?>(null)
|
||||
var zodiac by mutableStateOf<String?>(null)
|
||||
suspend fun reloadProfile(updateTrtcProfile:Boolean = false) {
|
||||
// 保存原始值,用于取消时恢复
|
||||
private var originalName: String = ""
|
||||
private var originalBio: String = ""
|
||||
private var originalMbti: String? = null
|
||||
private var originalZodiac: String? = null
|
||||
suspend fun reloadProfile(updateTrtcProfile:Boolean = false, clearCroppedBitmap: Boolean = false) {
|
||||
Log.d("AccountEditViewModel", "reloadProfile: 开始加载用户资料")
|
||||
isLoading = true
|
||||
try {
|
||||
@@ -41,13 +46,23 @@ object AccountEditViewModel : ViewModel() {
|
||||
profile = it
|
||||
name = it.nickName
|
||||
bio = it.bio
|
||||
// 清除之前裁剪的图片
|
||||
// 保存原始值,用于取消时恢复
|
||||
originalName = it.nickName
|
||||
originalBio = it.bio
|
||||
// 只在明确要求时清除之前裁剪的图片(例如保存成功后)
|
||||
if (clearCroppedBitmap) {
|
||||
croppedBitmap = null
|
||||
}
|
||||
// 读取本地扩展字段
|
||||
try {
|
||||
val uid = it.id // 使用 profile 的 id,确保非空
|
||||
mbti = com.aiosman.ravenow.AppStore.getUserMbti(uid)
|
||||
zodiac = com.aiosman.ravenow.AppStore.getUserZodiac(uid)
|
||||
val loadedMbti = com.aiosman.ravenow.AppStore.getUserMbti(uid)
|
||||
val loadedZodiac = com.aiosman.ravenow.AppStore.getUserZodiac(uid)
|
||||
mbti = loadedMbti
|
||||
zodiac = loadedZodiac
|
||||
// 保存原始值
|
||||
originalMbti = loadedMbti
|
||||
originalZodiac = loadedZodiac
|
||||
} catch (_: Exception) { }
|
||||
if (updateTrtcProfile) {
|
||||
TrtcHelper.updateTrtcProfile(
|
||||
@@ -69,12 +84,15 @@ object AccountEditViewModel : ViewModel() {
|
||||
}
|
||||
|
||||
fun resetToOriginalData() {
|
||||
profile?.let {
|
||||
name = it.nickName
|
||||
bio = it.bio
|
||||
// 清除之前裁剪的图片
|
||||
// 恢复所有字段到原始值
|
||||
name = originalName
|
||||
bio = originalBio
|
||||
mbti = originalMbti
|
||||
zodiac = originalZodiac
|
||||
// 清除之前裁剪的图片和壁纸
|
||||
croppedBitmap = null
|
||||
}
|
||||
bannerImageUrl = null
|
||||
bannerFile = null
|
||||
}
|
||||
|
||||
|
||||
@@ -129,8 +147,8 @@ object AccountEditViewModel : ViewModel() {
|
||||
// 清除背景图状态
|
||||
bannerImageUrl = null
|
||||
bannerFile = null
|
||||
// 刷新用户资料
|
||||
reloadProfile()
|
||||
// 刷新用户资料,保存成功后清除裁剪的图片
|
||||
reloadProfile(clearCroppedBitmap = true)
|
||||
// 刷新个人资料页面的用户资料
|
||||
MyProfileViewModel.loadUserProfile()
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ import com.aiosman.ravenow.ConstVars
|
||||
import com.aiosman.ravenow.ui.composables.pickupAndCompressLauncher
|
||||
import android.widget.Toast
|
||||
import java.io.File
|
||||
import androidx.activity.compose.BackHandler
|
||||
|
||||
/**
|
||||
* 编辑用户资料界面
|
||||
@@ -171,6 +172,13 @@ fun AccountEditScreen2(onUpdateBanner: ((Uri, File, Context) -> Unit)? = null,)
|
||||
model.reloadProfile()
|
||||
}
|
||||
|
||||
// 处理系统返回键
|
||||
BackHandler {
|
||||
// 用户未保存直接返回,恢复所有字段到原始值
|
||||
model.resetToOriginalData()
|
||||
navController.navigateUp()
|
||||
}
|
||||
|
||||
// 设置状态栏为透明,根据暗色模式决定图标颜色
|
||||
val systemUiController = rememberSystemUiController()
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -291,6 +299,8 @@ fun AccountEditScreen2(onUpdateBanner: ((Uri, File, Context) -> Unit)? = null,)
|
||||
.clip(CircleShape)
|
||||
.background(Color.White.copy(alpha = 0.3f))
|
||||
.noRippleClickable {
|
||||
// 用户未保存直接返回,恢复所有字段到原始值
|
||||
model.resetToOriginalData()
|
||||
navController.navigateUp()
|
||||
}
|
||||
.align(Alignment.CenterStart),
|
||||
|
||||
@@ -6,8 +6,10 @@ import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
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.layout.width
|
||||
@@ -15,10 +17,14 @@ import androidx.compose.foundation.layout.wrapContentWidth
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.aiosman.ravenow.LocalAppTheme
|
||||
@@ -75,30 +81,51 @@ fun UnderlineTabItem(
|
||||
) {
|
||||
val AppColors = LocalAppTheme.current
|
||||
|
||||
// 动画化字体大小和padding
|
||||
val animatedFontSize by animateFloatAsState(
|
||||
targetValue = if (isSelected) 17f else 15f,
|
||||
animationSpec = tween(durationMillis = 200),
|
||||
label = "fontSize"
|
||||
)
|
||||
val animatedPadding by animateDpAsState(
|
||||
targetValue = if (isSelected) 20.dp else 16.dp,
|
||||
animationSpec = tween(durationMillis = 200),
|
||||
label = "padding"
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.noRippleClickable { onClick() },
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = animatedPadding)
|
||||
.padding(top = 13.dp, bottom = 0.dp),
|
||||
contentAlignment = Alignment.BottomCenter
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
fontSize = 15.sp,
|
||||
fontSize = animatedFontSize.sp,
|
||||
fontWeight = FontWeight.ExtraBold,
|
||||
color = if (isSelected) AppColors.text else AppColors.text.copy(alpha = 0.6f),
|
||||
modifier = Modifier.padding(horizontal = 16.dp).padding(top = 13.dp)
|
||||
textAlign = androidx.compose.ui.text.style.TextAlign.Center
|
||||
)
|
||||
}
|
||||
|
||||
// 选中状态下显示图标
|
||||
if (isSelected) {
|
||||
Box(
|
||||
modifier = Modifier.size(24.dp),
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.offset(y = (-4).dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
if (isSelected) {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.underline),
|
||||
contentDescription = "selected indicator",
|
||||
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,8 @@ fun ImageCropScreen() {
|
||||
}
|
||||
}
|
||||
if (uri == null) {
|
||||
// 用户取消图片选择,清除已裁剪的图片
|
||||
AccountEditViewModel.croppedBitmap = null
|
||||
navController.popBackStack()
|
||||
}
|
||||
}
|
||||
@@ -103,6 +105,8 @@ fun ImageCropScreen() {
|
||||
painter = painterResource(R.drawable.rider_pro_back_icon),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.clickable {
|
||||
// 用户取消头像选择,清除已裁剪的图片
|
||||
AccountEditViewModel.croppedBitmap = null
|
||||
navController.popBackStack()
|
||||
},
|
||||
colorFilter = ColorFilter.tint(Color.White)
|
||||
@@ -119,13 +123,11 @@ fun ImageCropScreen() {
|
||||
val bitmap = it.onCrop()
|
||||
|
||||
// 专门处理个人资料头像
|
||||
// 只设置裁剪后的图片,不立即上传,等待用户在编辑资料界面点击保存
|
||||
AccountEditViewModel.croppedBitmap = bitmap
|
||||
AccountEditViewModel.viewModelScope.launch {
|
||||
AccountEditViewModel.updateUserProfile(context)
|
||||
navController.popBackStack()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
Box(
|
||||
|
||||
@@ -121,35 +121,88 @@ fun AllChatListScreen() {
|
||||
var isLoading by remember { mutableStateOf(false) }
|
||||
var error by remember { mutableStateOf<String?>(null) }
|
||||
|
||||
// 监听各个 ViewModel 的列表变化
|
||||
val agentChatList = AgentChatListViewModel.agentChatList
|
||||
val groupChatList = GroupChatListViewModel.groupChatList
|
||||
val friendChatList = FriendChatListViewModel.friendChatList
|
||||
|
||||
// 当列表变化时,自动更新合并列表
|
||||
LaunchedEffect(agentChatList, groupChatList, friendChatList) {
|
||||
val combinedList = mutableListOf<CombinedConversation>()
|
||||
|
||||
agentChatList.forEach { agent ->
|
||||
combinedList.add(CombinedConversation(type = "agent", agentConversation = agent))
|
||||
}
|
||||
|
||||
groupChatList.forEach { group ->
|
||||
combinedList.add(CombinedConversation(type = "group", groupConversation = group))
|
||||
}
|
||||
|
||||
friendChatList.forEach { friend ->
|
||||
val isDuplicate = combinedList.any {
|
||||
it.type == "agent" && it.agentConversation?.trtcUserId == friend.trtcUserId
|
||||
}
|
||||
|
||||
if (!isDuplicate) {
|
||||
combinedList.add(CombinedConversation(type = "friend", friendConversation = friend))
|
||||
}
|
||||
}
|
||||
|
||||
// 按最后消息时间排序
|
||||
val sortedList = combinedList.sortedByDescending {
|
||||
it.lastMessageTime
|
||||
}
|
||||
|
||||
allConversations = sortedList
|
||||
}
|
||||
|
||||
// 监听加载状态
|
||||
val isAnyLoading = AgentChatListViewModel.isLoading ||
|
||||
GroupChatListViewModel.isLoading ||
|
||||
FriendChatListViewModel.isLoading
|
||||
|
||||
// 当加载状态变化时,更新 isLoading
|
||||
LaunchedEffect(isAnyLoading) {
|
||||
if (isAnyLoading) {
|
||||
// 如果有任何数据正在加载,确保显示加载状态
|
||||
if (!isLoading) {
|
||||
isLoading = true
|
||||
}
|
||||
} else {
|
||||
// 所有数据加载完成
|
||||
if (isLoading) {
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val state = rememberPullRefreshState(
|
||||
refreshing = refreshing,
|
||||
onRefresh = {
|
||||
refreshing = true
|
||||
refreshAllData(context,
|
||||
onSuccess = { conversations ->
|
||||
allConversations = conversations
|
||||
refreshing = false
|
||||
},
|
||||
onError = { errorMsg ->
|
||||
error = errorMsg
|
||||
refreshing = false
|
||||
}
|
||||
)
|
||||
// 刷新所有类型的数据
|
||||
AgentChatListViewModel.refreshPager(pullRefresh = true, context = context)
|
||||
GroupChatListViewModel.refreshPager(pullRefresh = true, context = context)
|
||||
FriendChatListViewModel.refreshPager(pullRefresh = true, context = context)
|
||||
}
|
||||
)
|
||||
|
||||
// 监听刷新状态
|
||||
LaunchedEffect(AgentChatListViewModel.refreshing, GroupChatListViewModel.refreshing, FriendChatListViewModel.refreshing) {
|
||||
val isAnyRefreshing = AgentChatListViewModel.refreshing ||
|
||||
GroupChatListViewModel.refreshing ||
|
||||
FriendChatListViewModel.refreshing
|
||||
if (!isAnyRefreshing && refreshing) {
|
||||
refreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
isLoading = true
|
||||
refreshAllData(context,
|
||||
onSuccess = { conversations ->
|
||||
allConversations = conversations
|
||||
isLoading = false
|
||||
},
|
||||
onError = { errorMsg ->
|
||||
error = errorMsg
|
||||
isLoading = false
|
||||
}
|
||||
)
|
||||
// 初始化加载所有类型的数据
|
||||
AgentChatListViewModel.refreshPager(context = context)
|
||||
GroupChatListViewModel.refreshPager(context = context)
|
||||
FriendChatListViewModel.refreshPager(context = context)
|
||||
}
|
||||
|
||||
Column(
|
||||
@@ -235,16 +288,10 @@ fun AllChatListScreen() {
|
||||
ReloadButton(
|
||||
onClick = {
|
||||
isLoading = true
|
||||
refreshAllData(context,
|
||||
onSuccess = { conversations ->
|
||||
allConversations = conversations
|
||||
isLoading = false
|
||||
},
|
||||
onError = { errorMsg ->
|
||||
error = errorMsg
|
||||
isLoading = false
|
||||
}
|
||||
)
|
||||
// 重新加载所有类型的数据
|
||||
AgentChatListViewModel.refreshPager(context = context)
|
||||
GroupChatListViewModel.refreshPager(context = context)
|
||||
FriendChatListViewModel.refreshPager(context = context)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -363,44 +410,3 @@ fun AllChatListScreen() {
|
||||
}
|
||||
}
|
||||
|
||||
fun refreshAllData(
|
||||
context: android.content.Context,
|
||||
onSuccess: (List<CombinedConversation>) -> Unit,
|
||||
onError: (String) -> Unit
|
||||
) {
|
||||
try {
|
||||
// 同时刷新所有类型的数据
|
||||
AgentChatListViewModel.refreshPager(context = context)
|
||||
GroupChatListViewModel.refreshPager(context = context)
|
||||
FriendChatListViewModel.refreshPager(context = context)
|
||||
|
||||
val combinedList = mutableListOf<CombinedConversation>()
|
||||
|
||||
AgentChatListViewModel.agentChatList.forEach { agent ->
|
||||
combinedList.add(CombinedConversation(type = "agent", agentConversation = agent))
|
||||
}
|
||||
|
||||
GroupChatListViewModel.groupChatList.forEach { group ->
|
||||
combinedList.add(CombinedConversation(type = "group", groupConversation = group))
|
||||
}
|
||||
|
||||
FriendChatListViewModel.friendChatList.forEach { friend ->
|
||||
val isDuplicate = combinedList.any {//判断重复
|
||||
it.type == "agent" && it.agentConversation?.trtcUserId == friend.trtcUserId
|
||||
}
|
||||
|
||||
if (!isDuplicate) {
|
||||
combinedList.add(CombinedConversation(type = "friend", friendConversation = friend))
|
||||
}
|
||||
}
|
||||
|
||||
// 按最后消息时间排序
|
||||
val sortedList = combinedList.sortedByDescending {
|
||||
it.lastMessageTime
|
||||
}
|
||||
|
||||
onSuccess(sortedList)
|
||||
} catch (e: Exception) {
|
||||
onError("刷新数据失败: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ fun MomentsList(
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(44.dp)
|
||||
.height(54.dp)
|
||||
.padding(horizontal = 16.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
|
||||
@@ -390,7 +390,8 @@ fun NewsItem(
|
||||
NewsActionButton(
|
||||
icon = if (moment.isFavorite) R.mipmap.icon_variant_2 else R.mipmap.icon_collect,
|
||||
count = moment.favoriteCount.toString(),
|
||||
isActive = moment.isFavorite,
|
||||
isActive = false, // 收藏后不使用红色滤镜,保持图标原本颜色
|
||||
keepOriginalColor = moment.isFavorite, // 收藏后保持原始颜色
|
||||
modifier = Modifier.noRippleClickable { onFavoriteClick() }
|
||||
)
|
||||
|
||||
@@ -406,6 +407,9 @@ fun NewsItem(
|
||||
}
|
||||
}
|
||||
|
||||
// 激活状态的颜色(点赞/收藏时的红色)
|
||||
private val ActiveIconColor = Color(0xFFD80264)
|
||||
|
||||
// 互动栏按钮
|
||||
@Composable
|
||||
fun NewsActionButton(
|
||||
@@ -414,7 +418,8 @@ fun NewsActionButton(
|
||||
isActive: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
text: String? = null,
|
||||
textSize: androidx.compose.ui.unit.TextUnit = 12.sp
|
||||
textSize: androidx.compose.ui.unit.TextUnit = 12.sp,
|
||||
keepOriginalColor: Boolean = false // 是否保持原始颜色(不应用颜色滤镜)
|
||||
) {
|
||||
val AppColors = LocalAppTheme.current
|
||||
|
||||
@@ -432,7 +437,12 @@ fun NewsActionButton(
|
||||
Image(
|
||||
painter = androidx.compose.ui.res.painterResource(id = icon),
|
||||
contentDescription = "操作图标",
|
||||
modifier = Modifier.size(16.dp)
|
||||
modifier = Modifier.size(16.dp),
|
||||
colorFilter = when {
|
||||
isActive -> ColorFilter.tint(ActiveIconColor)
|
||||
keepOriginalColor -> null // 保持原始颜色
|
||||
else -> ColorFilter.tint(AppColors.text) // 未激活状态时使用文字颜色适配暗色模式
|
||||
}
|
||||
)
|
||||
|
||||
if (count.isNotEmpty()) {
|
||||
|
||||
@@ -69,14 +69,18 @@ import com.aiosman.ravenow.LocalAppTheme
|
||||
import com.aiosman.ravenow.LocalNavController
|
||||
import com.aiosman.ravenow.R
|
||||
import com.aiosman.ravenow.entity.AccountProfileEntity
|
||||
import com.aiosman.ravenow.GuestLoginCheckOut
|
||||
import com.aiosman.ravenow.GuestLoginCheckOutScene
|
||||
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
||||
import com.aiosman.ravenow.ui.composables.MomentCard
|
||||
import com.aiosman.ravenow.ui.composables.TabItem
|
||||
import com.aiosman.ravenow.ui.composables.TabSpacer
|
||||
import com.aiosman.ravenow.ui.composables.rememberDebouncer
|
||||
import com.aiosman.ravenow.ui.index.tabs.message.tab.AgentChatListViewModel
|
||||
import com.aiosman.ravenow.ui.index.tabs.profile.composable.RoomItem
|
||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
import com.aiosman.ravenow.ui.navigateToGroupChat
|
||||
import com.aiosman.ravenow.ui.NavigationRoute
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import kotlinx.coroutines.launch
|
||||
import com.aiosman.ravenow.utils.NetworkUtils
|
||||
@@ -403,6 +407,8 @@ fun MomentResultTab() {
|
||||
var moments = dataFlow.collectAsLazyPagingItems()
|
||||
val AppColors = LocalAppTheme.current
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val navController = LocalNavController.current
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
@@ -473,6 +479,12 @@ fun MomentResultTab() {
|
||||
) {
|
||||
items(moments.itemCount) { idx ->
|
||||
val momentItem = moments[idx] ?: return@items
|
||||
|
||||
val commentDebouncer = rememberDebouncer()
|
||||
val likeDebouncer = rememberDebouncer()
|
||||
val favoriteDebouncer = rememberDebouncer()
|
||||
val followDebouncer = rememberDebouncer()
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -480,10 +492,61 @@ fun MomentResultTab() {
|
||||
) {
|
||||
MomentCard(
|
||||
momentEntity = momentItem,
|
||||
hideAction = true,
|
||||
onAddComment = {
|
||||
commentDebouncer {
|
||||
// 检查游客模式,如果是游客则跳转登录
|
||||
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.COMMENT_MOMENT)) {
|
||||
navController.navigate(NavigationRoute.Login.route)
|
||||
} else {
|
||||
scope.launch {
|
||||
model.onAddComment(momentItem.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onLikeClick = {
|
||||
likeDebouncer {
|
||||
// 检查游客模式,如果是游客则跳转登录
|
||||
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
|
||||
navController.navigate(NavigationRoute.Login.route)
|
||||
} else {
|
||||
scope.launch {
|
||||
if (momentItem.liked) {
|
||||
model.dislikeMoment(momentItem.id)
|
||||
} else {
|
||||
model.likeMoment(momentItem.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onFavoriteClick = {
|
||||
favoriteDebouncer {
|
||||
// 检查游客模式,如果是游客则跳转登录
|
||||
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
|
||||
navController.navigate(NavigationRoute.Login.route)
|
||||
} else {
|
||||
scope.launch {
|
||||
if (momentItem.isFavorite) {
|
||||
model.unfavoriteMoment(momentItem.id)
|
||||
} else {
|
||||
model.favoriteMoment(momentItem.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onFollowClick = {
|
||||
followDebouncer {
|
||||
// 检查游客模式,如果是游客则跳转登录
|
||||
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.FOLLOW_USER)) {
|
||||
navController.navigate(NavigationRoute.Login.route)
|
||||
} else {
|
||||
model.momentFollowAction(momentItem)
|
||||
}
|
||||
}
|
||||
},
|
||||
showFollowButton = true
|
||||
)
|
||||
}
|
||||
// Spacer(modifier = Modifier.padding(16.dp))
|
||||
@@ -663,6 +726,8 @@ fun AiResultTab() {
|
||||
val context = LocalContext.current
|
||||
val model = SearchViewModel
|
||||
val agents = model.agentsFlow.collectAsLazyPagingItems()
|
||||
val navController = LocalNavController.current
|
||||
val scope = rememberCoroutineScope()
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
@@ -736,7 +801,23 @@ fun AiResultTab() {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
.padding(16.dp)
|
||||
.noRippleClickable {
|
||||
scope.launch {
|
||||
try {
|
||||
val userService = com.aiosman.ravenow.data.UserServiceImpl()
|
||||
val profile = userService.getUserProfileByOpenId(agent.openId)
|
||||
navController.navigate(
|
||||
NavigationRoute.AccountProfile.route
|
||||
.replace("{id}", profile.id.toString())
|
||||
.replace("{isAiAccount}", "true")
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
// 处理错误
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
CustomAsyncImage(
|
||||
|
||||
@@ -200,4 +200,88 @@ object SearchViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun likeMoment(id: Int) {
|
||||
try {
|
||||
momentService.likeMoment(id)
|
||||
updateMomentLike(id, true)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun dislikeMoment(id: Int) {
|
||||
try {
|
||||
momentService.dislikeMoment(id)
|
||||
updateMomentLike(id, false)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun favoriteMoment(id: Int) {
|
||||
try {
|
||||
momentService.favoriteMoment(id)
|
||||
updateMomentFavorite(id, true)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun unfavoriteMoment(id: Int) {
|
||||
try {
|
||||
momentService.unfavoriteMoment(id)
|
||||
updateMomentFavorite(id, false)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun onAddComment(id: Int) {
|
||||
updateMomentCommentCount(id, 1)
|
||||
}
|
||||
|
||||
private fun updateMomentLike(id: Int, isLike: Boolean) {
|
||||
val currentPagingData = _momentsFlow.value
|
||||
val updatedPagingData = currentPagingData.map { momentItem ->
|
||||
if (momentItem.id == id) {
|
||||
momentItem.copy(
|
||||
liked = isLike,
|
||||
likeCount = momentItem.likeCount + if (isLike) 1 else -1
|
||||
)
|
||||
} else {
|
||||
momentItem
|
||||
}
|
||||
}
|
||||
_momentsFlow.value = updatedPagingData
|
||||
}
|
||||
|
||||
private fun updateMomentFavorite(id: Int, isFavorite: Boolean) {
|
||||
val currentPagingData = _momentsFlow.value
|
||||
val updatedPagingData = currentPagingData.map { momentItem ->
|
||||
if (momentItem.id == id) {
|
||||
momentItem.copy(
|
||||
isFavorite = isFavorite,
|
||||
favoriteCount = momentItem.favoriteCount + if (isFavorite) 1 else -1
|
||||
)
|
||||
} else {
|
||||
momentItem
|
||||
}
|
||||
}
|
||||
_momentsFlow.value = updatedPagingData
|
||||
}
|
||||
|
||||
private fun updateMomentCommentCount(id: Int, delta: Int) {
|
||||
val currentPagingData = _momentsFlow.value
|
||||
val updatedPagingData = currentPagingData.map { momentItem ->
|
||||
if (momentItem.id == id) {
|
||||
momentItem.copy(
|
||||
commentCount = (momentItem.commentCount + delta).coerceAtLeast(0)
|
||||
)
|
||||
} else {
|
||||
momentItem
|
||||
}
|
||||
}
|
||||
_momentsFlow.value = updatedPagingData
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,7 @@ import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -453,6 +454,7 @@ private fun PointsHistoryList(
|
||||
hasNext: Boolean
|
||||
) {
|
||||
val AppColors = LocalAppTheme.current
|
||||
val context = LocalContext.current
|
||||
val numberFormat = remember { NumberFormat.getNumberInstance(Locale.getDefault()) }
|
||||
val listState = rememberLazyListState()
|
||||
val loading = PointsViewModel.loading
|
||||
@@ -544,7 +546,7 @@ private fun PointsHistoryList(
|
||||
)
|
||||
Spacer(Modifier.size(12.dp))
|
||||
Column {
|
||||
Text(text = PointService.getReasonDescription(item.reason ?: "" ), color = AppColors.text, fontSize = 16.sp, fontWeight = FontWeight.W600)
|
||||
Text(text = PointService.getReasonDescription(context, item.reason ?: "" ), color = AppColors.text, fontSize = 16.sp, fontWeight = FontWeight.W600)
|
||||
Spacer(Modifier.height(4.dp))
|
||||
Text(text = item.createdAt ?: "", color = AppColors.secondaryText, fontSize = 12.sp)
|
||||
}
|
||||
|
||||
@@ -362,6 +362,21 @@
|
||||
<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">エージェントプライベートモード</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="create_group_chat_failed">グループチャットの作成に失敗しました: %1$s</string>
|
||||
<string name="connect_world_start_following">世界をつなぐ、フォローから始めましょう</string>
|
||||
<string name="why_not_start_with_agent">エージェントから世界を知り始めませんか?</string>
|
||||
|
||||
@@ -367,6 +367,21 @@
|
||||
<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>
|
||||
|
||||
@@ -361,6 +361,21 @@
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user