Merge upstream/main and resolve conflicts
This commit is contained in:
2
.idea/kotlinc.xml
generated
2
.idea/kotlinc.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="KotlinJpsPluginSettings">
|
<component name="KotlinJpsPluginSettings">
|
||||||
<option name="version" value="1.9.0" />
|
<option name="version" value="1.9.10" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -41,7 +41,9 @@ data class AgentMomentRequestBody(
|
|||||||
|
|
||||||
data class SingleChatRequestBody(
|
data class SingleChatRequestBody(
|
||||||
@SerializedName("agentOpenId")
|
@SerializedName("agentOpenId")
|
||||||
val generateText: String,
|
val generateText: String? = null,
|
||||||
|
@SerializedName("agentTrtcId")
|
||||||
|
val agentTrtcId: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class GroupChatRequestBody(
|
data class GroupChatRequestBody(
|
||||||
@@ -561,6 +563,11 @@ interface RaveNowAPI {
|
|||||||
@Query("isRecommended") isRecommended: Int = 1,
|
@Query("isRecommended") isRecommended: Int = 1,
|
||||||
): Response<ListContainer<Room>>
|
): Response<ListContainer<Room>>
|
||||||
|
|
||||||
|
@GET("outside/rooms/detail")
|
||||||
|
suspend fun getRoomDetail(@Query("trtcId") trtcId: String,
|
||||||
|
): Response<DataContainer<Room>>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
15
app/src/main/java/com/aiosman/ravenow/entity/Group.kt
Normal file
15
app/src/main/java/com/aiosman/ravenow/entity/Group.kt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package com.aiosman.ravenow.entity
|
||||||
|
|
||||||
|
data class GroupMember(
|
||||||
|
val userId: String,
|
||||||
|
val nickname: String,
|
||||||
|
val avatar: String,
|
||||||
|
val isOwner: Boolean = false
|
||||||
|
)
|
||||||
|
|
||||||
|
data class GroupInfo(
|
||||||
|
val groupId: String,
|
||||||
|
val groupName: String,
|
||||||
|
val groupAvatar: String,
|
||||||
|
val memberCount: Int,
|
||||||
|
)
|
||||||
@@ -35,6 +35,7 @@ import com.aiosman.ravenow.ui.agent.AddAgentScreen
|
|||||||
import com.aiosman.ravenow.ui.group.CreateGroupChatScreen
|
import com.aiosman.ravenow.ui.group.CreateGroupChatScreen
|
||||||
import com.aiosman.ravenow.ui.chat.ChatAiScreen
|
import com.aiosman.ravenow.ui.chat.ChatAiScreen
|
||||||
import com.aiosman.ravenow.ui.chat.ChatScreen
|
import com.aiosman.ravenow.ui.chat.ChatScreen
|
||||||
|
import com.aiosman.ravenow.ui.group.GroupChatInfoScreen
|
||||||
import com.aiosman.ravenow.ui.chat.GroupChatScreen
|
import com.aiosman.ravenow.ui.chat.GroupChatScreen
|
||||||
import com.aiosman.ravenow.ui.comment.CommentsScreen
|
import com.aiosman.ravenow.ui.comment.CommentsScreen
|
||||||
import com.aiosman.ravenow.ui.comment.notice.CommentNoticeScreen
|
import com.aiosman.ravenow.ui.comment.notice.CommentNoticeScreen
|
||||||
@@ -96,6 +97,7 @@ sealed class NavigationRoute(
|
|||||||
data object Chat : NavigationRoute("Chat/{id}")
|
data object Chat : NavigationRoute("Chat/{id}")
|
||||||
data object ChatAi : NavigationRoute("ChatAi/{id}")
|
data object ChatAi : NavigationRoute("ChatAi/{id}")
|
||||||
data object ChatGroup : NavigationRoute("ChatGroup/{id}/{name}/{avatar}")
|
data object ChatGroup : NavigationRoute("ChatGroup/{id}/{name}/{avatar}")
|
||||||
|
data object GroupChatInfo : NavigationRoute("GroupChatInfo/{groupId}")
|
||||||
data object CommentNoticeScreen : NavigationRoute("CommentNoticeScreen")
|
data object CommentNoticeScreen : NavigationRoute("CommentNoticeScreen")
|
||||||
data object ImageCrop : NavigationRoute("ImageCrop")
|
data object ImageCrop : NavigationRoute("ImageCrop")
|
||||||
data object AccountSetting : NavigationRoute("AccountSetting")
|
data object AccountSetting : NavigationRoute("AccountSetting")
|
||||||
@@ -404,6 +406,19 @@ fun NavigationController(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
composable(
|
||||||
|
route = NavigationRoute.GroupChatInfo.route,
|
||||||
|
arguments = listOf(navArgument("groupId") { type = NavType.StringType })
|
||||||
|
) {
|
||||||
|
val encodedId = it.arguments?.getString("groupId")
|
||||||
|
val decodedId = encodedId?.let { java.net.URLDecoder.decode(it, "UTF-8") }
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalAnimatedContentScope provides this,
|
||||||
|
) {
|
||||||
|
GroupChatInfoScreen(decodedId?:"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
composable(route = NavigationRoute.CommentNoticeScreen.route) {
|
composable(route = NavigationRoute.CommentNoticeScreen.route) {
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
@@ -514,6 +529,15 @@ fun NavHostController.navigateToGroupChat(id: String,name:String,avatar:String)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun NavHostController.navigateToGroupInfo(id: String) {
|
||||||
|
val encodedId = java.net.URLEncoder.encode(id, "UTF-8")
|
||||||
|
navigate(
|
||||||
|
route = NavigationRoute.GroupChatInfo.route
|
||||||
|
.replace("{groupId}", encodedId)
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun NavHostController.goTo(
|
fun NavHostController.goTo(
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import androidx.activity.compose.rememberLauncherForActivityResult
|
|||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.animation.core.animateDpAsState
|
import androidx.compose.animation.core.animateDpAsState
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
@@ -49,6 +50,7 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.runtime.snapshotFlow
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.shadow
|
import androidx.compose.ui.draw.shadow
|
||||||
import androidx.compose.ui.focus.onFocusChanged
|
import androidx.compose.ui.focus.onFocusChanged
|
||||||
@@ -175,7 +177,7 @@ fun ChatScreen(userId: String) {
|
|||||||
Image(
|
Image(
|
||||||
painter = painterResource(R.drawable.rider_pro_back_icon),
|
painter = painterResource(R.drawable.rider_pro_back_icon),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(28.dp)
|
.size(24.dp)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
navController.navigateUp()
|
navController.navigateUp()
|
||||||
},
|
},
|
||||||
@@ -187,8 +189,8 @@ fun ChatScreen(userId: String) {
|
|||||||
CustomAsyncImage(
|
CustomAsyncImage(
|
||||||
imageUrl = viewModel.userProfile?.avatar ?: "",
|
imageUrl = viewModel.userProfile?.avatar ?: "",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(40.dp)
|
.size(32.dp)
|
||||||
.clip(RoundedCornerShape(40.dp)),
|
.clip(RoundedCornerShape(32.dp)),
|
||||||
contentDescription = "avatar"
|
contentDescription = "avatar"
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
@@ -221,7 +223,7 @@ fun ChatScreen(userId: String) {
|
|||||||
},
|
},
|
||||||
menuItems = listOf(
|
menuItems = listOf(
|
||||||
MenuItem(
|
MenuItem(
|
||||||
title = if (viewModel.notificationStrategy == "mute") "Unmute" else "Mute",
|
title = if (viewModel.notificationStrategy == "mute") "" else "",
|
||||||
icon = if (viewModel.notificationStrategy == "mute") R.drawable.rider_pro_notice_mute else R.drawable.rider_pro_notice_active,
|
icon = if (viewModel.notificationStrategy == "mute") R.drawable.rider_pro_notice_mute else R.drawable.rider_pro_notice_active,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -251,8 +253,7 @@ fun ChatScreen(userId: String) {
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(1.dp)
|
.height(1.dp)
|
||||||
.background(
|
|
||||||
AppColors.decentBackground)
|
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
ChatInput(
|
ChatInput(
|
||||||
@@ -270,13 +271,12 @@ fun ChatScreen(userId: String) {
|
|||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(AppColors.decentBackground)
|
.background(AppColors.background)
|
||||||
.padding(paddingValues)
|
.padding(paddingValues)
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = listState,
|
state = listState,
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxSize(),
|
||||||
.fillMaxSize(),
|
|
||||||
reverseLayout = true,
|
reverseLayout = true,
|
||||||
verticalArrangement = Arrangement.Top
|
verticalArrangement = Arrangement.Top
|
||||||
) {
|
) {
|
||||||
@@ -340,6 +340,7 @@ fun ChatScreen(userId: String) {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ChatSelfItem(item: ChatItem) {
|
fun ChatSelfItem(item: ChatItem) {
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -353,19 +354,28 @@ fun ChatSelfItem(item: ChatItem) {
|
|||||||
Column(
|
Column(
|
||||||
horizontalAlignment = androidx.compose.ui.Alignment.End,
|
horizontalAlignment = androidx.compose.ui.Alignment.End,
|
||||||
) {
|
) {
|
||||||
|
/* Text(
|
||||||
|
text = item.nickname,
|
||||||
|
style = TextStyle(
|
||||||
|
color = Color.Gray,
|
||||||
|
fontSize = 12.sp,
|
||||||
|
),
|
||||||
|
modifier = Modifier.padding(bottom = 2.dp)
|
||||||
|
)
|
||||||
|
*/
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.widthIn(
|
.widthIn(
|
||||||
min = 20.dp,
|
min = 20.dp,
|
||||||
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
||||||
)
|
)
|
||||||
.clip(RoundedCornerShape(8.dp))
|
.clip(RoundedCornerShape(20.dp))
|
||||||
.background(Color(0xFF000000))
|
.background(Color(0xFF6246FF))
|
||||||
.padding(
|
.padding(
|
||||||
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
||||||
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
||||||
)
|
)
|
||||||
.padding(bottom = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 3.dp else 0.dp))
|
|
||||||
) {
|
) {
|
||||||
when (item.messageType) {
|
when (item.messageType) {
|
||||||
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
||||||
@@ -373,7 +383,7 @@ fun ChatSelfItem(item: ChatItem) {
|
|||||||
text = item.message,
|
text = item.message,
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
color = Color.White,
|
color = Color.White,
|
||||||
fontSize = 16.sp,
|
fontSize = 14.sp,
|
||||||
),
|
),
|
||||||
textAlign = TextAlign.Start
|
textAlign = TextAlign.Start
|
||||||
)
|
)
|
||||||
@@ -389,28 +399,28 @@ fun ChatSelfItem(item: ChatItem) {
|
|||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
Text(
|
Text(
|
||||||
text = "Unsupported message type",
|
text = "不支持的消息类型",
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
color = Color.White,
|
color = Color.White,
|
||||||
fontSize = 16.sp,
|
fontSize = 14.sp,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.width(12.dp))
|
/*Spacer(modifier = Modifier.width(12.dp))
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(40.dp)
|
.size(24.dp)
|
||||||
.clip(RoundedCornerShape(40.dp))
|
.clip(RoundedCornerShape(24.dp))
|
||||||
) {
|
) {
|
||||||
CustomAsyncImage(
|
CustomAsyncImage(
|
||||||
imageUrl = item.avatar,
|
imageUrl = item.avatar,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
contentDescription = "avatar"
|
contentDescription = "avatar"
|
||||||
)
|
)
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -430,11 +440,11 @@ fun ChatOtherItem(item: ChatItem) {
|
|||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(40.dp)
|
.size(24.dp)
|
||||||
.clip(RoundedCornerShape(40.dp))
|
.clip(RoundedCornerShape(24.dp))
|
||||||
) {
|
) {
|
||||||
CustomAsyncImage(
|
CustomAsyncImage(
|
||||||
imageUrl = item.avatar,
|
imageUrl = item.avatar.replace("storage/avatars/", "/avatar/"),
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
contentDescription = "avatar"
|
contentDescription = "avatar"
|
||||||
)
|
)
|
||||||
@@ -447,13 +457,12 @@ fun ChatOtherItem(item: ChatItem) {
|
|||||||
min = 20.dp,
|
min = 20.dp,
|
||||||
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
||||||
)
|
)
|
||||||
.clip(RoundedCornerShape(8.dp))
|
.clip(RoundedCornerShape(20.dp))
|
||||||
.background(AppColors.background)
|
.background(AppColors.bubbleBackground)
|
||||||
.padding(
|
.padding(
|
||||||
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
||||||
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
||||||
)
|
)
|
||||||
.padding(bottom = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 3.dp else 0.dp))
|
|
||||||
) {
|
) {
|
||||||
when (item.messageType) {
|
when (item.messageType) {
|
||||||
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
||||||
@@ -461,7 +470,7 @@ fun ChatOtherItem(item: ChatItem) {
|
|||||||
text = item.message,
|
text = item.message,
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
fontSize = 16.sp,
|
fontSize = 14.sp,
|
||||||
),
|
),
|
||||||
textAlign = TextAlign.Start
|
textAlign = TextAlign.Start
|
||||||
)
|
)
|
||||||
@@ -477,7 +486,7 @@ fun ChatOtherItem(item: ChatItem) {
|
|||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
Text(
|
Text(
|
||||||
text = "Unsupported message type",
|
text = "不支持的消息类型",
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
@@ -486,7 +495,6 @@ fun ChatOtherItem(item: ChatItem) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -547,20 +555,21 @@ fun ChatInput(
|
|||||||
onSendImage(uri)
|
onSendImage(uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Box( modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(start = 16.dp, end = 16.dp, bottom = 12.dp),){
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp)
|
.clip(RoundedCornerShape(20.dp))
|
||||||
.padding(bottom = inputBarHeight)
|
.background(appColors.decentBackground)
|
||||||
|
.padding(start = 16.dp, end = 8.dp, top = 2.dp, bottom = 2.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.clip(RoundedCornerShape(16.dp))
|
|
||||||
.background(appColors.background)
|
|
||||||
.padding(horizontal = 16.dp),
|
|
||||||
contentAlignment = Alignment.CenterStart,
|
|
||||||
) {
|
) {
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
value = text,
|
value = text,
|
||||||
@@ -572,6 +581,7 @@ fun ChatInput(
|
|||||||
fontSize = 16.sp
|
fontSize = 16.sp
|
||||||
),
|
),
|
||||||
cursorBrush = SolidColor(appColors.text),
|
cursorBrush = SolidColor(appColors.text),
|
||||||
|
singleLine = true,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 8.dp)
|
.padding(vertical = 8.dp)
|
||||||
@@ -594,10 +604,10 @@ fun ChatInput(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.width(16.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Icon(
|
Image(
|
||||||
painter = painterResource(id = R.drawable.rider_pro_camera),
|
painter = painterResource(R.mipmap.rider_pro_im_image),
|
||||||
contentDescription = "Emoji",
|
contentDescription = "Image",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(30.dp)
|
.size(30.dp)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
@@ -610,28 +620,33 @@ fun ChatInput(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
tint = appColors.chatActionColor
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Crossfade(
|
Crossfade(
|
||||||
targetState = text.isNotEmpty(), animationSpec = tween(500),
|
targetState = text.isNotEmpty(), animationSpec = tween(500),
|
||||||
label = ""
|
label = ""
|
||||||
) { isNotEmpty ->
|
) { isNotEmpty ->
|
||||||
Icon(
|
val alpha by animateFloatAsState(
|
||||||
painter = painterResource(id = R.drawable.rider_pro_video_share),
|
targetValue = if (isNotEmpty) 1f else 0.5f,
|
||||||
contentDescription = "Emoji",
|
animationSpec = tween(300)
|
||||||
|
)
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.mipmap.rider_pro_im_send),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(32.dp)
|
.size(24.dp)
|
||||||
|
.alpha(alpha)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
if (text.isNotEmpty()) {
|
if (text.isNotEmpty()) {
|
||||||
onSend(text)
|
onSend(text)
|
||||||
text = ""
|
text = ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tint = if (isNotEmpty) appColors.main else appColors.chatActionColor
|
contentDescription = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun groupMessagesByTime(chatList: List<ChatItem>, viewModel: ChatViewModel): List<ChatItem> {
|
fun groupMessagesByTime(chatList: List<ChatItem>, viewModel: ChatViewModel): List<ChatItem> {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import androidx.activity.compose.rememberLauncherForActivityResult
|
|||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.animation.core.animateDpAsState
|
import androidx.compose.animation.core.animateDpAsState
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
@@ -49,6 +50,7 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.runtime.snapshotFlow
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.shadow
|
import androidx.compose.ui.draw.shadow
|
||||||
import androidx.compose.ui.focus.onFocusChanged
|
import androidx.compose.ui.focus.onFocusChanged
|
||||||
@@ -189,7 +191,7 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) {
|
|||||||
} else {
|
} else {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(40.dp)
|
.size(24.dp)
|
||||||
.clip(RoundedCornerShape(8.dp))
|
.clip(RoundedCornerShape(8.dp))
|
||||||
.background(AppColors.decentBackground),
|
.background(AppColors.decentBackground),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
@@ -234,34 +236,6 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) {
|
|||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(AppColors.text)
|
colorFilter = ColorFilter.tint(AppColors.text)
|
||||||
)
|
)
|
||||||
DropdownMenu(
|
|
||||||
expanded = isMenuExpanded,
|
|
||||||
onDismissRequest = {
|
|
||||||
isMenuExpanded = false
|
|
||||||
},
|
|
||||||
menuItems = listOf(
|
|
||||||
MenuItem(
|
|
||||||
title = if (viewModel.notificationStrategy == "mute") "取消静音" else "静音",
|
|
||||||
icon = if (viewModel.notificationStrategy == "mute") R.drawable.rider_pro_notice_mute else R.drawable.rider_pro_notice_active,
|
|
||||||
) {
|
|
||||||
isMenuExpanded = false
|
|
||||||
viewModel.viewModelScope.launch {
|
|
||||||
if (viewModel.notificationStrategy == "mute") {
|
|
||||||
viewModel.updateNotificationStrategy("active")
|
|
||||||
} else {
|
|
||||||
viewModel.updateNotificationStrategy("mute")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MenuItem(
|
|
||||||
title = "群成员",
|
|
||||||
icon = R.drawable.rider_pro_more_horizon,
|
|
||||||
) {
|
|
||||||
isMenuExpanded = false
|
|
||||||
viewModel.getGroupMembers()
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -276,9 +250,8 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) {
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(1.dp)
|
.height(1.dp)
|
||||||
.background(AppColors.decentBackground)
|
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
GroupChatInput(
|
GroupChatInput(
|
||||||
onSendImage = { uri ->
|
onSendImage = { uri ->
|
||||||
uri?.let {
|
uri?.let {
|
||||||
@@ -294,7 +267,7 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) {
|
|||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(AppColors.decentBackground)
|
.background(AppColors.background)
|
||||||
.padding(paddingValues)
|
.padding(paddingValues)
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
@@ -306,6 +279,7 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) {
|
|||||||
val chatList = groupMessagesByTime(viewModel.getDisplayChatList(), viewModel)
|
val chatList = groupMessagesByTime(viewModel.getDisplayChatList(), viewModel)
|
||||||
items(chatList.size, key = { index -> chatList[index].msgId + UUID.randomUUID().toString()}) { index ->
|
items(chatList.size, key = { index -> chatList[index].msgId + UUID.randomUUID().toString()}) { index ->
|
||||||
val item = chatList[index]
|
val item = chatList[index]
|
||||||
|
Column {
|
||||||
if (item.showTimeDivider) {
|
if (item.showTimeDivider) {
|
||||||
val calendar = java.util.Calendar.getInstance()
|
val calendar = java.util.Calendar.getInstance()
|
||||||
calendar.timeInMillis = item.timestamp
|
calendar.timeInMillis = item.timestamp
|
||||||
@@ -313,7 +287,7 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) {
|
|||||||
text = calendar.time.formatChatTime(context),
|
text = calendar.time.formatChatTime(context),
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
color = AppColors.secondaryText,
|
color = AppColors.secondaryText,
|
||||||
fontSize = 14.sp,
|
fontSize = 11.sp,
|
||||||
textAlign = TextAlign.Center
|
textAlign = TextAlign.Center
|
||||||
),
|
),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -321,8 +295,15 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) {
|
|||||||
.padding(vertical = 8.dp)
|
.padding(vertical = 8.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// 获取上一个item的userId,用于判断是否显示头像和昵称
|
||||||
GroupChatItem(item = item, viewModel.myProfile?.trtcUserId!!)
|
val previousItem = if (index < chatList.size - 1) chatList[index + 1] else null
|
||||||
|
val showAvatarAndNickname = previousItem?.userId != item.userId
|
||||||
|
GroupChatItem(
|
||||||
|
item = item,
|
||||||
|
currentUserId = viewModel.myProfile?.trtcUserId!!,
|
||||||
|
showAvatarAndNickname = showAvatarAndNickname
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,7 +326,7 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) {
|
|||||||
text = "${goToNewCount} 条新消息",
|
text = "${goToNewCount} 条新消息",
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
fontSize = 16.sp,
|
fontSize = 12.sp,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -390,7 +371,7 @@ fun GroupChatSelfItem(item: ChatItem) {
|
|||||||
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
||||||
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
||||||
)
|
)
|
||||||
.padding(bottom = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 3.dp else 0.dp))
|
|
||||||
) {
|
) {
|
||||||
when (item.messageType) {
|
when (item.messageType) {
|
||||||
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
||||||
@@ -441,7 +422,7 @@ fun GroupChatSelfItem(item: ChatItem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun GroupChatOtherItem(item: ChatItem) {
|
fun GroupChatOtherItem(item: ChatItem, showAvatarAndNickname: Boolean = true) {
|
||||||
val AppColors = LocalAppTheme.current
|
val AppColors = LocalAppTheme.current
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
@@ -453,6 +434,7 @@ fun GroupChatOtherItem(item: ChatItem) {
|
|||||||
horizontalArrangement = Arrangement.Start,
|
horizontalArrangement = Arrangement.Start,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
|
if (showAvatarAndNickname) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(24.dp)
|
.size(24.dp)
|
||||||
@@ -465,16 +447,11 @@ fun GroupChatOtherItem(item: ChatItem) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.width(12.dp))
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
|
} else {
|
||||||
|
// 当不显示头像时,添加左边距以保持消息对齐
|
||||||
|
Spacer(modifier = Modifier.width(36.dp))
|
||||||
|
}
|
||||||
Column {
|
Column {
|
||||||
Text(
|
|
||||||
text = item.nickname,
|
|
||||||
style = TextStyle(
|
|
||||||
color = AppColors.secondaryText,
|
|
||||||
fontSize = 12.sp,
|
|
||||||
),
|
|
||||||
modifier = Modifier.padding(bottom = 2.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.widthIn(
|
.widthIn(
|
||||||
@@ -487,7 +464,6 @@ fun GroupChatOtherItem(item: ChatItem) {
|
|||||||
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
||||||
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
||||||
)
|
)
|
||||||
.padding(bottom = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 3.dp else 0.dp))
|
|
||||||
) {
|
) {
|
||||||
when (item.messageType) {
|
when (item.messageType) {
|
||||||
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
||||||
@@ -520,13 +496,24 @@ fun GroupChatOtherItem(item: ChatItem) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (showAvatarAndNickname) {
|
||||||
|
Text(
|
||||||
|
text = item.nickname,
|
||||||
|
style = TextStyle(
|
||||||
|
color = AppColors.secondaryText,
|
||||||
|
fontSize = 12.sp,
|
||||||
|
),
|
||||||
|
modifier = Modifier.padding(bottom = 2.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun GroupChatItem(item: ChatItem, currentUserId: String) {
|
fun GroupChatItem(item: ChatItem, currentUserId: String, showAvatarAndNickname: Boolean = true) {
|
||||||
val isCurrentUser = item.userId == currentUserId
|
val isCurrentUser = item.userId == currentUserId
|
||||||
|
|
||||||
// 管理员消息显示特殊布局
|
// 管理员消息显示特殊布局
|
||||||
@@ -538,7 +525,7 @@ fun GroupChatItem(item: ChatItem, currentUserId: String) {
|
|||||||
// 根据是否是当前用户显示不同样式
|
// 根据是否是当前用户显示不同样式
|
||||||
when (item.userId) {
|
when (item.userId) {
|
||||||
currentUserId -> GroupChatSelfItem(item)
|
currentUserId -> GroupChatSelfItem(item)
|
||||||
else -> GroupChatOtherItem(item)
|
else -> GroupChatOtherItem(item, showAvatarAndNickname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,20 +602,21 @@ fun GroupChatInput(
|
|||||||
onSendImage(uri)
|
onSendImage(uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Box( modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(start = 16.dp, end = 16.dp, bottom = 12.dp),){
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp)
|
.clip(RoundedCornerShape(20.dp))
|
||||||
.padding(bottom = inputBarHeight)
|
.background(appColors.decentBackground)
|
||||||
|
.padding(start = 16.dp, end = 8.dp, top = 2.dp, bottom = 2.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.clip(RoundedCornerShape(16.dp))
|
|
||||||
.background(appColors.background)
|
|
||||||
.padding(horizontal = 16.dp),
|
|
||||||
contentAlignment = Alignment.CenterStart,
|
|
||||||
) {
|
) {
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
value = text,
|
value = text,
|
||||||
@@ -640,6 +628,7 @@ fun GroupChatInput(
|
|||||||
fontSize = 16.sp
|
fontSize = 16.sp
|
||||||
),
|
),
|
||||||
cursorBrush = SolidColor(appColors.text),
|
cursorBrush = SolidColor(appColors.text),
|
||||||
|
singleLine = true,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 8.dp)
|
.padding(vertical = 8.dp)
|
||||||
@@ -662,44 +651,32 @@ fun GroupChatInput(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.width(16.dp))
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(id = R.drawable.rider_pro_camera),
|
|
||||||
contentDescription = "发送图片",
|
|
||||||
modifier = Modifier
|
|
||||||
.size(30.dp)
|
|
||||||
.noRippleClickable {
|
|
||||||
imagePickUpLauncher.launch(
|
|
||||||
Intent.createChooser(
|
|
||||||
Intent(Intent.ACTION_GET_CONTENT).apply {
|
|
||||||
type = "image/*"
|
|
||||||
},
|
|
||||||
"选择图片"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
tint = appColors.chatActionColor
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Crossfade(
|
Crossfade(
|
||||||
targetState = text.isNotEmpty(), animationSpec = tween(500),
|
targetState = text.isNotEmpty(), animationSpec = tween(500),
|
||||||
label = ""
|
label = ""
|
||||||
) { isNotEmpty ->
|
) { isNotEmpty ->
|
||||||
Icon(
|
val alpha by animateFloatAsState(
|
||||||
painter = painterResource(id = R.drawable.rider_pro_video_share),
|
targetValue = if (isNotEmpty) 1f else 0.5f,
|
||||||
contentDescription = "发送消息",
|
animationSpec = tween(300)
|
||||||
|
)
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.mipmap.rider_pro_im_send),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(32.dp)
|
.size(24.dp)
|
||||||
|
.alpha(alpha)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
if (text.isNotEmpty()) {
|
if (text.isNotEmpty()) {
|
||||||
onSend(text)
|
onSend(text)
|
||||||
text = ""
|
text = ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tint = if (isNotEmpty) appColors.main else appColors.chatActionColor
|
contentDescription = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun groupMessagesByTime(chatList: List<ChatItem>, viewModel: GroupChatViewModel): List<ChatItem> {
|
fun groupMessagesByTime(chatList: List<ChatItem>, viewModel: GroupChatViewModel): List<ChatItem> {
|
||||||
@@ -711,7 +688,7 @@ fun groupMessagesByTime(chatList: List<ChatItem>, viewModel: GroupChatViewModel)
|
|||||||
}
|
}
|
||||||
val currentMessage = chatList[i]
|
val currentMessage = chatList[i]
|
||||||
val timeDiff = currentMessage.timestamp - chatList[i - 1].timestamp
|
val timeDiff = currentMessage.timestamp - chatList[i - 1].timestamp
|
||||||
if (-timeDiff > 30 * 60 * 1000) {
|
if (-timeDiff > 10 * 60 * 1000) {
|
||||||
viewModel.showTimestampMap[currentMessage.msgId] = true
|
viewModel.showTimestampMap[currentMessage.msgId] = true
|
||||||
currentMessage.showTimeDivider = true
|
currentMessage.showTimeDivider = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ class GroupChatViewModel(
|
|||||||
var isLoading by mutableStateOf(false)
|
var isLoading by mutableStateOf(false)
|
||||||
var lastMessage: V2TIMMessage? = null
|
var lastMessage: V2TIMMessage? = null
|
||||||
val showTimestampMap = mutableMapOf<String, Boolean>()
|
val showTimestampMap = mutableMapOf<String, Boolean>()
|
||||||
var chatNotification by mutableStateOf<ChatNotification?>(null)
|
|
||||||
var goToNew by mutableStateOf(false)
|
var goToNew by mutableStateOf(false)
|
||||||
|
|
||||||
// 群聊特有属性
|
// 群聊特有属性
|
||||||
@@ -71,8 +70,6 @@ class GroupChatViewModel(
|
|||||||
myProfile = accountService.getMyAccountProfile()
|
myProfile = accountService.getMyAccountProfile()
|
||||||
RegistListener(context)
|
RegistListener(context)
|
||||||
fetchHistoryMessage(context)
|
fetchHistoryMessage(context)
|
||||||
val notiStrategy = ChatState.getStrategyByTargetTrtcId(groupId)
|
|
||||||
chatNotification = notiStrategy
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("GroupChatViewModel", "初始化失败: ${e.message}")
|
Log.e("GroupChatViewModel", "初始化失败: ${e.message}")
|
||||||
}
|
}
|
||||||
@@ -287,16 +284,4 @@ class GroupChatViewModel(
|
|||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateNotificationStrategy(strategy: String) {
|
|
||||||
val result = ChatState.updateChatNotification(groupId.hashCode(), strategy)
|
|
||||||
chatNotification = result
|
|
||||||
}
|
|
||||||
|
|
||||||
val notificationStrategy get() = chatNotification?.strategy ?: "default"
|
|
||||||
|
|
||||||
// 群聊特有功能
|
|
||||||
fun getGroupMembers() {
|
|
||||||
// 简化群成员获取,暂时只记录日志
|
|
||||||
Log.d("GroupChatViewModel", "获取群成员功能待实现")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,328 @@
|
|||||||
|
package com.aiosman.ravenow.ui.group
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
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.graphics.ColorFilter
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
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.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import com.aiosman.ravenow.LocalAppTheme
|
||||||
|
import com.aiosman.ravenow.LocalNavController
|
||||||
|
import com.aiosman.ravenow.R
|
||||||
|
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
||||||
|
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
|
||||||
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun GroupChatInfoScreen(groupId: String) {
|
||||||
|
val navController = LocalNavController.current
|
||||||
|
val context = LocalContext.current
|
||||||
|
val AppColors = LocalAppTheme.current
|
||||||
|
|
||||||
|
val viewModel = viewModel<GroupChatInfoViewModel>(
|
||||||
|
key = "GroupChatInfoViewModel_$groupId",
|
||||||
|
factory = object : ViewModelProvider.Factory {
|
||||||
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
|
return GroupChatInfoViewModel(groupId) as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(AppColors.background)
|
||||||
|
) {
|
||||||
|
// 顶部导航栏
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(AppColors.background)
|
||||||
|
) {
|
||||||
|
StatusBarSpacer()
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 16.dp, horizontal = 16.dp),
|
||||||
|
horizontalArrangement = Arrangement.Start,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.rider_pro_back_icon),
|
||||||
|
modifier = Modifier
|
||||||
|
.size(24.dp)
|
||||||
|
.noRippleClickable {
|
||||||
|
navController.navigateUp()
|
||||||
|
},
|
||||||
|
contentDescription = null,
|
||||||
|
colorFilter = ColorFilter.tint(AppColors.text)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
textAlign = TextAlign.Start,
|
||||||
|
text = "群聊信息",
|
||||||
|
style = androidx.compose.ui.text.TextStyle(
|
||||||
|
color = AppColors.text,
|
||||||
|
fontSize = 17.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(40.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 内容区域
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentPadding = PaddingValues(16.dp)
|
||||||
|
) {
|
||||||
|
// 群聊头像和名称
|
||||||
|
item {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
if (viewModel.groupInfo?.groupAvatar?.isNotEmpty() == true) {
|
||||||
|
CustomAsyncImage(
|
||||||
|
imageUrl = viewModel.groupInfo!!.groupAvatar,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(80.dp)
|
||||||
|
.clip(RoundedCornerShape(12.dp)),
|
||||||
|
contentDescription = "群聊头像"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(80.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(AppColors.decentBackground),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = viewModel.groupInfo?.groupName?.firstOrNull()?.toString() ?: "群",
|
||||||
|
style = androidx.compose.ui.text.TextStyle(
|
||||||
|
color = AppColors.text,
|
||||||
|
fontSize = 24.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = viewModel.groupInfo?.groupName ?: "群聊",
|
||||||
|
style = androidx.compose.ui.text.TextStyle(
|
||||||
|
color = AppColors.text,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 操作按钮
|
||||||
|
item {
|
||||||
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceEvenly
|
||||||
|
) {
|
||||||
|
// 添加其他人
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.noRippleClickable {
|
||||||
|
// TODO: 实现添加其他人功能
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
.clip(CircleShape),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.rider_pro_add_other),
|
||||||
|
modifier = Modifier.size(24.dp),
|
||||||
|
contentDescription = null,
|
||||||
|
colorFilter = ColorFilter.tint(
|
||||||
|
AppColors.text)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.group_info_add_other),
|
||||||
|
style = androidx.compose.ui.text.TextStyle(
|
||||||
|
color = AppColors.text,
|
||||||
|
fontSize = 12.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通知设置
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.noRippleClickable {
|
||||||
|
/* if (viewModel.notificationStrategy == "mute") {
|
||||||
|
viewModel.updateNotificationStrategy("active")
|
||||||
|
} else {
|
||||||
|
viewModel.updateNotificationStrategy("mute")
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
.clip(CircleShape),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(if (viewModel.notificationStrategy == "mute") R.drawable.rider_pro_notice_mute else R.drawable.rider_pro_notice_active,),
|
||||||
|
modifier = Modifier.size(24.dp),
|
||||||
|
contentDescription = null,
|
||||||
|
colorFilter = ColorFilter.tint(
|
||||||
|
AppColors.text)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.group_info_notice_setting),
|
||||||
|
style = androidx.compose.ui.text.TextStyle(
|
||||||
|
color = AppColors.text,
|
||||||
|
fontSize = 12.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 退出群聊
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.noRippleClickable {
|
||||||
|
// TODO: 实现退出群聊功能
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
.clip(CircleShape),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.group_info_exit
|
||||||
|
),
|
||||||
|
modifier = Modifier.size(24.dp),
|
||||||
|
contentDescription = null,
|
||||||
|
colorFilter = ColorFilter.tint(
|
||||||
|
AppColors.text)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.group_info_exit),
|
||||||
|
style = androidx.compose.ui.text.TextStyle(
|
||||||
|
color = AppColors.text,
|
||||||
|
fontSize = 12.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置选项
|
||||||
|
item {
|
||||||
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
|
||||||
|
// 设置聊天主题
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clip(RoundedCornerShape(8.dp))
|
||||||
|
.padding(16.dp)
|
||||||
|
.noRippleClickable {
|
||||||
|
// TODO: 实现设置聊天主题功能
|
||||||
|
},
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.group_info_edit),
|
||||||
|
modifier = Modifier.size(24.dp),
|
||||||
|
contentDescription = null,
|
||||||
|
colorFilter = ColorFilter.tint(
|
||||||
|
AppColors.text)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.group_info_edit),
|
||||||
|
style = androidx.compose.ui.text.TextStyle(
|
||||||
|
color = AppColors.text,
|
||||||
|
fontSize = 16.sp
|
||||||
|
),
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.rave_now_nav_right),
|
||||||
|
modifier = Modifier.size(18.dp),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(1.dp))
|
||||||
|
|
||||||
|
// 群聊成员
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clip(RoundedCornerShape(8.dp))
|
||||||
|
.padding(16.dp)
|
||||||
|
.noRippleClickable {
|
||||||
|
// TODO: 实现查看群聊成员功能
|
||||||
|
},
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.group_info_users),
|
||||||
|
modifier = Modifier.size(24.dp),
|
||||||
|
contentDescription = null,
|
||||||
|
colorFilter = ColorFilter.tint(
|
||||||
|
AppColors.text)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
|
Text(
|
||||||
|
text = "群聊成员 (${viewModel.groupInfo?.memberCount ?: 0})",
|
||||||
|
style = androidx.compose.ui.text.TextStyle(
|
||||||
|
color = AppColors.text,
|
||||||
|
fontSize = 16.sp
|
||||||
|
),
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.rave_now_nav_right),
|
||||||
|
modifier = Modifier.size(18.dp),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package com.aiosman.ravenow.ui.group
|
||||||
|
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.aiosman.ravenow.AppStore
|
||||||
|
import com.aiosman.ravenow.ChatState
|
||||||
|
import com.aiosman.ravenow.data.api.ApiClient
|
||||||
|
import com.aiosman.ravenow.entity.ChatNotification
|
||||||
|
import com.aiosman.ravenow.entity.GroupInfo
|
||||||
|
import com.aiosman.ravenow.entity.GroupMember
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class GroupChatInfoViewModel(
|
||||||
|
private val groupId: String
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
|
var groupInfo by mutableStateOf<GroupInfo?>(null)
|
||||||
|
var isLoading by mutableStateOf(false)
|
||||||
|
var error by mutableStateOf<String?>(null)
|
||||||
|
var chatNotification by mutableStateOf<ChatNotification?>(null)
|
||||||
|
val notificationStrategy get() = chatNotification?.strategy ?: "default"
|
||||||
|
init {
|
||||||
|
loadGroupInfo()
|
||||||
|
}
|
||||||
|
suspend fun updateNotificationStrategy(strategy: String) {
|
||||||
|
val result = ChatState.updateChatNotification(groupId.hashCode(), strategy)
|
||||||
|
chatNotification = result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun loadGroupInfo() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val notiStrategy = ChatState.getStrategyByTargetTrtcId(groupId)
|
||||||
|
chatNotification = notiStrategy
|
||||||
|
try {
|
||||||
|
isLoading = true
|
||||||
|
error = null
|
||||||
|
|
||||||
|
// 调用接口获取群聊详情
|
||||||
|
val response = ApiClient.api.getRoomDetail(trtcId = groupId)
|
||||||
|
|
||||||
|
// 使用接口返回的数据
|
||||||
|
val room = response.body()?.data
|
||||||
|
groupInfo = room?.let {
|
||||||
|
GroupInfo(
|
||||||
|
groupId = groupId,
|
||||||
|
groupName = it.name,
|
||||||
|
groupAvatar = if (it.avatar.isNullOrEmpty()) {
|
||||||
|
// 将 groupId 转换为 Base64
|
||||||
|
val groupIdBase64 = android.util.Base64.encodeToString(
|
||||||
|
groupId.toByteArray(),
|
||||||
|
android.util.Base64.NO_WRAP
|
||||||
|
)
|
||||||
|
"${ApiClient.RETROFIT_URL+"group/avatar?groupIdBase64="}${groupIdBase64}"+"&token="+"${AppStore.token}"
|
||||||
|
} else {
|
||||||
|
"${ApiClient.BASE_API_URL+"/outside/rooms/avatar/"}${it.avatar}"+"?token="+"${AppStore.token}"
|
||||||
|
},
|
||||||
|
memberCount = room.userCount,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
error = e.message ?: "加载失败"
|
||||||
|
} finally {
|
||||||
|
isLoading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,8 +21,10 @@ import androidx.compose.foundation.layout.requiredWidth
|
|||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.DrawerValue
|
import androidx.compose.material3.DrawerValue
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
@@ -55,6 +57,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.offset
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.aiosman.ravenow.AppState
|
import com.aiosman.ravenow.AppState
|
||||||
import com.aiosman.ravenow.AppStore
|
import com.aiosman.ravenow.AppStore
|
||||||
@@ -66,6 +69,9 @@ import com.aiosman.ravenow.ui.NavigationRoute
|
|||||||
import com.aiosman.ravenow.ui.index.tabs.add.AddPage
|
import com.aiosman.ravenow.ui.index.tabs.add.AddPage
|
||||||
import com.aiosman.ravenow.ui.index.tabs.ai.Agent
|
import com.aiosman.ravenow.ui.index.tabs.ai.Agent
|
||||||
import com.aiosman.ravenow.ui.index.tabs.message.NotificationsScreen
|
import com.aiosman.ravenow.ui.index.tabs.message.NotificationsScreen
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.message.tab.AgentChatListViewModel
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.message.tab.FriendChatListViewModel
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.message.tab.GroupChatListViewModel
|
||||||
import com.aiosman.ravenow.ui.index.tabs.moment.MomentsList
|
import com.aiosman.ravenow.ui.index.tabs.moment.MomentsList
|
||||||
import com.aiosman.ravenow.ui.index.tabs.profile.ProfileWrap
|
import com.aiosman.ravenow.ui.index.tabs.profile.ProfileWrap
|
||||||
import com.aiosman.ravenow.ui.index.tabs.search.DiscoverScreen
|
import com.aiosman.ravenow.ui.index.tabs.search.DiscoverScreen
|
||||||
@@ -99,6 +105,10 @@ fun IndexScreen() {
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
systemUiController.setNavigationBarColor(Color.Transparent)
|
systemUiController.setNavigationBarColor(Color.Transparent)
|
||||||
|
// 初始化聊天列表以获取未读消息数
|
||||||
|
AgentChatListViewModel.refreshPager(context = context)
|
||||||
|
GroupChatListViewModel.refreshPager(context = context)
|
||||||
|
FriendChatListViewModel.refreshPager(context = context)
|
||||||
}
|
}
|
||||||
LaunchedEffect(model.openDrawer) {
|
LaunchedEffect(model.openDrawer) {
|
||||||
if (model.openDrawer) {
|
if (model.openDrawer) {
|
||||||
@@ -310,6 +320,13 @@ fun IndexScreen() {
|
|||||||
shape = RoundedCornerShape(12.dp)
|
shape = RoundedCornerShape(12.dp)
|
||||||
),
|
),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(24.dp)
|
||||||
|
.height(24.dp)
|
||||||
|
,
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(if (isSelected) it.selectedIcon() else it.icon()),
|
painter = painterResource(if (isSelected) it.selectedIcon() else it.icon()),
|
||||||
@@ -317,6 +334,27 @@ fun IndexScreen() {
|
|||||||
modifier = Modifier.size(24.dp),
|
modifier = Modifier.size(24.dp),
|
||||||
colorFilter = if (!isSelected) ColorFilter.tint(AppColors.text) else null
|
colorFilter = if (!isSelected) ColorFilter.tint(AppColors.text) else null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 消息按钮红点显示在图片右上角
|
||||||
|
if (it.route == NavigationItem.Notification.route) {
|
||||||
|
val totalUnreadCount =
|
||||||
|
AgentChatListViewModel.totalUnreadCount +
|
||||||
|
GroupChatListViewModel.totalUnreadCount +
|
||||||
|
FriendChatListViewModel.totalUnreadCount
|
||||||
|
if (totalUnreadCount > 0) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(8.dp)
|
||||||
|
.background(
|
||||||
|
color = Color(0xFFFF3B30),
|
||||||
|
shape = CircleShape
|
||||||
|
)
|
||||||
|
.align(Alignment.TopEnd)
|
||||||
|
.offset(x = 8.dp, y = 8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 文字标签,可控制间距
|
// 文字标签,可控制间距
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.systemBars
|
import androidx.compose.foundation.layout.systemBars
|
||||||
@@ -50,6 +52,7 @@ import androidx.compose.ui.text.font.FontWeight
|
|||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.compose.ui.unit.offset
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.aiosman.ravenow.AppState
|
import com.aiosman.ravenow.AppState
|
||||||
import com.aiosman.ravenow.AppStore
|
import com.aiosman.ravenow.AppStore
|
||||||
@@ -63,8 +66,11 @@ import com.aiosman.ravenow.ui.composables.TabItem
|
|||||||
import com.aiosman.ravenow.ui.composables.TabSpacer
|
import com.aiosman.ravenow.ui.composables.TabSpacer
|
||||||
import com.aiosman.ravenow.ui.follower.FollowerNoticeViewModel
|
import com.aiosman.ravenow.ui.follower.FollowerNoticeViewModel
|
||||||
import com.aiosman.ravenow.ui.index.tabs.message.tab.AgentChatListScreen
|
import com.aiosman.ravenow.ui.index.tabs.message.tab.AgentChatListScreen
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.message.tab.AgentChatListViewModel
|
||||||
import com.aiosman.ravenow.ui.index.tabs.message.tab.FriendChatListScreen
|
import com.aiosman.ravenow.ui.index.tabs.message.tab.FriendChatListScreen
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.message.tab.FriendChatListViewModel
|
||||||
import com.aiosman.ravenow.ui.index.tabs.message.tab.GroupChatListScreen
|
import com.aiosman.ravenow.ui.index.tabs.message.tab.GroupChatListScreen
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.message.tab.GroupChatListViewModel
|
||||||
import com.aiosman.ravenow.ui.like.LikeNoticeViewModel
|
import com.aiosman.ravenow.ui.like.LikeNoticeViewModel
|
||||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
@@ -77,6 +83,10 @@ import kotlinx.coroutines.launch
|
|||||||
@OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun NotificationsScreen() {
|
fun NotificationsScreen() {
|
||||||
|
// 计算总未读消息数
|
||||||
|
val totalUnreadCount = AgentChatListViewModel.totalUnreadCount +
|
||||||
|
GroupChatListViewModel.totalUnreadCount +
|
||||||
|
FriendChatListViewModel.totalUnreadCount
|
||||||
val AppColors = LocalAppTheme.current
|
val AppColors = LocalAppTheme.current
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
@@ -87,6 +97,12 @@ fun NotificationsScreen() {
|
|||||||
MessageListViewModel.viewModelScope.launch {
|
MessageListViewModel.viewModelScope.launch {
|
||||||
MessageListViewModel.initData(context, force = true, loadChat = AppState.enableChat)
|
MessageListViewModel.initData(context, force = true, loadChat = AppState.enableChat)
|
||||||
}
|
}
|
||||||
|
// 刷新群聊列表以更新未读消息数
|
||||||
|
GroupChatListViewModel.refreshPager(context = context)
|
||||||
|
// 刷新智能体列表以更新未读消息数
|
||||||
|
AgentChatListViewModel.refreshPager(context = context)
|
||||||
|
// 刷新朋友列表以更新未读消息数
|
||||||
|
FriendChatListViewModel.refreshPager(context = context)
|
||||||
})
|
})
|
||||||
val navigationBarPaddings =
|
val navigationBarPaddings =
|
||||||
WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 48.dp
|
WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 48.dp
|
||||||
@@ -94,6 +110,12 @@ fun NotificationsScreen() {
|
|||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
systemUiController.setNavigationBarColor(Color.Transparent)
|
systemUiController.setNavigationBarColor(Color.Transparent)
|
||||||
MessageListViewModel.initData(context, loadChat = AppState.enableChat)
|
MessageListViewModel.initData(context, loadChat = AppState.enableChat)
|
||||||
|
// 初始化群聊列表以获取未读消息数
|
||||||
|
GroupChatListViewModel.refreshPager(context = context)
|
||||||
|
// 初始化智能体列表以获取未读消息数
|
||||||
|
AgentChatListViewModel.refreshPager(context = context)
|
||||||
|
// 初始化朋友列表以获取未读消息数
|
||||||
|
FriendChatListViewModel.refreshPager(context = context)
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -202,6 +224,7 @@ fun NotificationsScreen() {
|
|||||||
horizontalArrangement = Arrangement.Start,
|
horizontalArrangement = Arrangement.Start,
|
||||||
verticalAlignment = Alignment.Bottom
|
verticalAlignment = Alignment.Bottom
|
||||||
) {
|
) {
|
||||||
|
Box {
|
||||||
TabItem(
|
TabItem(
|
||||||
text = stringResource(R.string.chat_ai),
|
text = stringResource(R.string.chat_ai),
|
||||||
isSelected = pagerState.currentPage == 0,
|
isSelected = pagerState.currentPage == 0,
|
||||||
@@ -209,10 +232,25 @@ fun NotificationsScreen() {
|
|||||||
scope.launch {
|
scope.launch {
|
||||||
pagerState.animateScrollToPage(0)
|
pagerState.animateScrollToPage(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 智能体未读消息红点
|
||||||
|
if (AgentChatListViewModel.totalUnreadCount > 0) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(8.dp)
|
||||||
|
.background(
|
||||||
|
color = Color(0xFFFF3B30),
|
||||||
|
shape = CircleShape
|
||||||
|
)
|
||||||
|
.align(Alignment.TopEnd)
|
||||||
|
.offset(x = 8.dp, y = (-4).dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
TabSpacer()
|
TabSpacer()
|
||||||
|
Box {
|
||||||
TabItem(
|
TabItem(
|
||||||
text = stringResource(R.string.chat_group),
|
text = stringResource(R.string.chat_group),
|
||||||
isSelected = pagerState.currentPage == 1,
|
isSelected = pagerState.currentPage == 1,
|
||||||
@@ -222,7 +260,23 @@ fun NotificationsScreen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 群聊未读消息红点
|
||||||
|
if (GroupChatListViewModel.totalUnreadCount > 0) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(8.dp)
|
||||||
|
.background(
|
||||||
|
color = Color(0xFFFF3B30),
|
||||||
|
shape = CircleShape
|
||||||
|
)
|
||||||
|
.align(Alignment.TopEnd)
|
||||||
|
.offset(x = 8.dp, y = (-4).dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
TabSpacer()
|
TabSpacer()
|
||||||
|
Box {
|
||||||
TabItem(
|
TabItem(
|
||||||
text = stringResource(R.string.chat_friend),
|
text = stringResource(R.string.chat_friend),
|
||||||
isSelected = pagerState.currentPage == 2,
|
isSelected = pagerState.currentPage == 2,
|
||||||
@@ -232,6 +286,21 @@ fun NotificationsScreen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 朋友未读消息红点
|
||||||
|
if (FriendChatListViewModel.totalUnreadCount > 0) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(8.dp)
|
||||||
|
.background(
|
||||||
|
color = Color(0xFFFF3B30),
|
||||||
|
shape = CircleShape
|
||||||
|
)
|
||||||
|
.align(Alignment.TopEnd)
|
||||||
|
.offset(x = 8.dp, y = (-4).dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
HorizontalPager(
|
HorizontalPager(
|
||||||
state = pagerState,
|
state = pagerState,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.aiosman.ravenow.ui.index.tabs.message.tab
|
package com.aiosman.ravenow.ui.index.tabs.message.tab
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
@@ -29,7 +30,9 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -38,6 +41,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import com.aiosman.ravenow.LocalAppTheme
|
import com.aiosman.ravenow.LocalAppTheme
|
||||||
import com.aiosman.ravenow.LocalNavController
|
import com.aiosman.ravenow.LocalNavController
|
||||||
import com.aiosman.ravenow.R
|
import com.aiosman.ravenow.R
|
||||||
|
import com.aiosman.ravenow.ui.NavigationRoute
|
||||||
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
||||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
|
|
||||||
@@ -82,8 +86,16 @@ fun AgentChatListScreen() {
|
|||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.Center
|
|
||||||
) {
|
) {
|
||||||
|
Spacer(modifier = Modifier.height(80.dp))
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.mipmap.icon_agent_chat_empty),
|
||||||
|
contentDescription = "null data",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(140.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.agent_chat_empty_title),
|
text = stringResource(R.string.agent_chat_empty_title),
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
@@ -93,7 +105,7 @@ fun AgentChatListScreen() {
|
|||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.agent_chat_empty_subtitle),
|
text = stringResource(R.string.agent_chat_empty_subtitle),
|
||||||
color = AppColors.secondaryText,
|
color = AppColors.text,
|
||||||
fontSize = 14.sp
|
fontSize = 14.sp
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,10 @@ object AgentChatListViewModel : ViewModel() {
|
|||||||
var currentPage by mutableStateOf(1)
|
var currentPage by mutableStateOf(1)
|
||||||
var error by mutableStateOf<String?>(null)
|
var error by mutableStateOf<String?>(null)
|
||||||
|
|
||||||
|
// 计算智能体总未读消息数
|
||||||
|
val totalUnreadCount: Int
|
||||||
|
get() = agentChatList.sumOf { it.unreadCount }
|
||||||
|
|
||||||
private val pageSize = 20
|
private val pageSize = 20
|
||||||
|
|
||||||
fun refreshPager(pullRefresh: Boolean = false, context: Context? = null) {
|
fun refreshPager(pullRefresh: Boolean = false, context: Context? = null) {
|
||||||
@@ -200,10 +204,10 @@ object AgentChatListViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun createSingleChat(
|
fun createSingleChat(
|
||||||
openId: String,
|
trtcId: String,
|
||||||
) {
|
) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val response = ApiClient.api.createSingleChat(SingleChatRequestBody(generateText = openId))
|
val response = ApiClient.api.createSingleChat(SingleChatRequestBody(agentTrtcId = trtcId))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.aiosman.ravenow.ui.index.tabs.message.tab
|
package com.aiosman.ravenow.ui.index.tabs.message.tab
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
@@ -20,6 +21,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
@@ -68,6 +70,15 @@ fun FriendChatListScreen() {
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.Center
|
verticalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(80.dp))
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.mipmap.icon_friend_chat_empty),
|
||||||
|
contentDescription = "null data",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(140.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.friend_chat_empty_title),
|
text = stringResource(R.string.friend_chat_empty_title),
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
@@ -77,7 +88,7 @@ fun FriendChatListScreen() {
|
|||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.friend_chat_empty_subtitle),
|
text = stringResource(R.string.friend_chat_empty_subtitle),
|
||||||
color = AppColors.secondaryText,
|
color = AppColors.text,
|
||||||
fontSize = 14.sp
|
fontSize = 14.sp
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,10 @@ object FriendChatListViewModel : ViewModel() {
|
|||||||
var currentPage by mutableStateOf(1)
|
var currentPage by mutableStateOf(1)
|
||||||
var error by mutableStateOf<String?>(null)
|
var error by mutableStateOf<String?>(null)
|
||||||
|
|
||||||
|
// 计算朋友总未读消息数
|
||||||
|
val totalUnreadCount: Int
|
||||||
|
get() = friendChatList.sumOf { it.unreadCount }
|
||||||
|
|
||||||
private val pageSize = 20
|
private val pageSize = 20
|
||||||
|
|
||||||
fun refreshPager(pullRefresh: Boolean = false, context: Context? = null) {
|
fun refreshPager(pullRefresh: Boolean = false, context: Context? = null) {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.aiosman.ravenow.ui.index.tabs.message.tab
|
package com.aiosman.ravenow.ui.index.tabs.message.tab
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
@@ -21,6 +23,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
@@ -78,16 +81,29 @@ fun GroupChatListScreen() {
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.Center
|
verticalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(80.dp))
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = if (isSystemInDarkTheme()) {
|
||||||
|
R.mipmap.icon_group_chat_empty // 深色模式图片
|
||||||
|
} else {
|
||||||
|
R.mipmap.icon_group_chat_empty // 浅色模式图片
|
||||||
|
}),
|
||||||
|
contentDescription = "null data",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(140.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
Text(
|
Text(
|
||||||
text = "暂无群聊",
|
text = stringResource(R.string.group_chat_empty_title),
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
fontWeight = FontWeight.W600
|
fontWeight = FontWeight.W600
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
Text(
|
Text(
|
||||||
text = "您还没有加入任何群聊",
|
text = stringResource(R.string.group_chat_empty_subtitle),
|
||||||
color = AppColors.secondaryText,
|
color = AppColors.text,
|
||||||
fontSize = 14.sp
|
fontSize = 14.sp
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,10 @@ object GroupChatListViewModel : ViewModel() {
|
|||||||
var currentPage by mutableStateOf(1)
|
var currentPage by mutableStateOf(1)
|
||||||
var error by mutableStateOf<String?>(null)
|
var error by mutableStateOf<String?>(null)
|
||||||
|
|
||||||
|
// 计算群聊总未读消息数
|
||||||
|
val totalUnreadCount: Int
|
||||||
|
get() = groupChatList.sumOf { it.unreadCount }
|
||||||
|
|
||||||
private val pageSize = 20
|
private val pageSize = 20
|
||||||
|
|
||||||
// 消息监听器
|
// 消息监听器
|
||||||
|
|||||||
@@ -270,6 +270,15 @@ fun Explore() {
|
|||||||
state = pagerState,
|
state = pagerState,
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
) { page ->
|
) { page ->
|
||||||
|
// 计算当前页面的偏移量
|
||||||
|
val pageOffset = (
|
||||||
|
(pagerState.currentPage - page) + pagerState
|
||||||
|
.currentPageOffsetFraction
|
||||||
|
).coerceIn(-1f, 1f)
|
||||||
|
|
||||||
|
// 根据偏移量计算缩放比例
|
||||||
|
val scale = 1f - (0.1f * kotlin.math.abs(pageOffset))
|
||||||
|
|
||||||
AgentPage(
|
AgentPage(
|
||||||
agentItems = agentItems.drop(page * itemsPerPage).take(itemsPerPage),
|
agentItems = agentItems.drop(page * itemsPerPage).take(itemsPerPage),
|
||||||
page = page
|
page = page
|
||||||
@@ -653,7 +662,19 @@ fun Explore() {
|
|||||||
contentDescription = "创建智能体",
|
contentDescription = "创建智能体",
|
||||||
modifier = Modifier.size(24.dp),
|
modifier = Modifier.size(24.dp),
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
)
|
)
|
||||||
|
=======
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.size(8.dp))
|
||||||
|
Text(
|
||||||
|
text = "发布动态",
|
||||||
|
fontSize = 12.sp,
|
||||||
|
color = AppColors.text,
|
||||||
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W500
|
||||||
|
)
|
||||||
|
>>>>>>> upstream/main
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.size(8.dp))
|
Spacer(modifier = Modifier.size(8.dp))
|
||||||
Text(
|
Text(
|
||||||
@@ -767,10 +788,35 @@ fun Explore() {
|
|||||||
) {
|
) {
|
||||||
HorizontalPager(
|
HorizontalPager(
|
||||||
state = pagerState,
|
state = pagerState,
|
||||||
|
<<<<<<< HEAD
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
) { page ->
|
) { page ->
|
||||||
val bannerItem = bannerItems[page]
|
val bannerItem = bannerItems[page]
|
||||||
BannerCard(bannerItem = bannerItem)
|
BannerCard(bannerItem = bannerItem)
|
||||||
|
=======
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentPadding = androidx.compose.foundation.layout.PaddingValues(horizontal = 4.dp),
|
||||||
|
) { page ->
|
||||||
|
val bannerItem = bannerItems[page]
|
||||||
|
|
||||||
|
// 计算当前页面的偏移量
|
||||||
|
val pageOffset = (
|
||||||
|
(pagerState.currentPage - page) + pagerState
|
||||||
|
.currentPageOffsetFraction
|
||||||
|
).coerceIn(-1f, 1f)
|
||||||
|
|
||||||
|
// 根据偏移量计算缩放比例
|
||||||
|
val scale = 1f - (0.1f * kotlin.math.abs(pageOffset))
|
||||||
|
|
||||||
|
BannerCard(
|
||||||
|
bannerItem = bannerItem,
|
||||||
|
modifier = Modifier
|
||||||
|
.graphicsLayer {
|
||||||
|
scaleX = scale
|
||||||
|
scaleY = scale
|
||||||
|
}
|
||||||
|
)
|
||||||
|
>>>>>>> upstream/main
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
35
app/src/main/res/drawable/group_info_edit.xml
Normal file
35
app/src/main/res/drawable/group_info_edit.xml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M 0 0 L 24 0 L 24 24 L 0 24 Z" />
|
||||||
|
<path
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M 15 8 L 15.01 8" />
|
||||||
|
<path
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M 7 4 L 17 4 Q 20 4 20 7 L 20 17 Q 20 20 17 20 L 7 20 Q 4 20 4 17 L 4 7 Q 4 4 7 4 Z" />
|
||||||
|
<path
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M4,15 L8,11 C8.92820323,10.106836 10.0717968,10.106836 11,11 L16,16" />
|
||||||
|
<path
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M14,14 L15,13 C15.9282032,12.106836 17.0717968,12.106836 18,13 L20,15" />
|
||||||
|
</vector>
|
||||||
25
app/src/main/res/drawable/group_info_exit.xml
Normal file
25
app/src/main/res/drawable/group_info_exit.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M0 0h24v24H0z" />
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#000"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M14 8V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h7a2 2 0 0 0 2-2v-2" />
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#000"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M7 12h14l-3-3m0 6 3-3" />
|
||||||
|
</vector>
|
||||||
15
app/src/main/res/drawable/group_info_notice_setting.xml
Normal file
15
app/src/main/res/drawable/group_info_notice_setting.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#000"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M21 16.5H3a2.7 2.7 0 0 0 2.7-2.7V9.3a6.3 6.3 0 0 1 12.6 0v4.5a2.7 2.7 0 0 0 2.7 2.7h0zm-7.443 3.6a1.8 1.8 0 0 1-3.114 0" />
|
||||||
|
</vector>
|
||||||
38
app/src/main/res/drawable/group_info_users.xml
Normal file
38
app/src/main/res/drawable/group_info_users.xml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
<group
|
||||||
|
android:translateX="2"
|
||||||
|
android:translateY="4">
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#000"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:pathData="M7.273 10.777c4.016 0 7.272 1.791 7.272 4 0 0.706-0.331 1.368-0.914 1.944-0.392 0.179 -0.828 0.278 -1.288 0.278 H2.202a3.1 3.1 0 0 1-1.288-0.278C0.332 16.145 0 15.483 0 14.777c0-2.209 3.256-4 7.273-4z" />
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#000"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M16.491 17h1.236c0.5 0 2.273-0.398 2.273-2.223 0-1.49-1.482-2.79-3.68-3.478" />
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#000"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M 7.273 0 C 9.28110735038 0 10.909 1.59162771435 10.909 3.555 C 10.909 5.51837228565 9.28110735038 7.11 7.273 7.11 C 5.26489264962 7.11 3.637 5.51837228565 3.637 3.555 C 3.637 1.59162771435 5.26489264962 0 7.273 0 Z" />
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#000"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M13.636 0.116 c1.61 0.402 2.735 1.82 2.735 3.444 0 1.624-1.126 3.041-2.735 3.444" />
|
||||||
|
</group>
|
||||||
|
</vector>
|
||||||
30
app/src/main/res/drawable/rider_pro_add_other.xml
Normal file
30
app/src/main/res/drawable/rider_pro_add_other.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
<group
|
||||||
|
android:translateX="2"
|
||||||
|
android:translateY="4">
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#110C13"
|
||||||
|
android:strokeWidth="1.778"
|
||||||
|
android:pathData="M7.273 10.777c4.016 0 7.272 1.791 7.272 4 0 0.706-0.331 1.368-0.914 1.944-0.392 0.179 -0.828 0.278 -1.288 0.278 H2.202a3.1 3.1 0 0 1-1.288-0.278C0.332 16.145 0 15.483 0 14.777c0-2.209 3.256-4 7.273-4z" />
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#110C13"
|
||||||
|
android:strokeWidth="1.778"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M 7.273 0 C 9.28110735038 0 10.909 1.59162771435 10.909 3.555 C 10.909 5.51837228565 9.28110735038 7.11 7.273 7.11 C 5.26489264962 7.11 3.637 5.51837228565 3.637 3.555 C 3.637 1.59162771435 5.26489264962 0 7.273 0 Z" />
|
||||||
|
</group>
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#110C13"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M16.364 10.945h6M19.364 7.945v6" />
|
||||||
|
</vector>
|
||||||
@@ -1,5 +1,21 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:alpha="0.77" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zM12,6.5c2.49,0 4,2.02 4,4.5v0.1l2,2L18,11c0,-3.07 -1.63,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68c-0.24,0.06 -0.47,0.15 -0.69,0.23l1.64,1.64c0.18,-0.02 0.36,-0.05 0.55,-0.05zM5.41,3.35L4,4.76l2.81,2.81C6.29,8.57 6,9.74 6,11v5l-2,2v1h14.24l1.74,1.74 1.41,-1.41L5.41,3.35zM16,17L8,17v-6c0,-0.68 0.12,-1.32 0.34,-1.9L16,16.76L16,17z"/>
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#000"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M16.06 16.5H3a2.7 2.7 0 0 0 2.7-2.7V9.3c0-0.913 0.194 -1.78 0.543 -2.563m2.564-2.87A6.3 6.3 0 0 1 18.3 9.3v4.5m-4.743 6.3a1.8 1.8 0 0 1-3.114 0" />
|
||||||
|
<path
|
||||||
|
android:strokeColor="#000"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M3 3 18.75 18.75" />
|
||||||
</vector>
|
</vector>
|
||||||
BIN
app/src/main/res/mipmap-xhdpi/icon_agent_chat_empty.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/icon_agent_chat_empty.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
BIN
app/src/main/res/mipmap-xhdpi/icon_friend_chat_empty.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/icon_friend_chat_empty.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
BIN
app/src/main/res/mipmap-xhdpi/icon_group_chat_empty.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/icon_group_chat_empty.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_im_image.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_im_image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_im_send.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_im_send.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
@@ -147,8 +147,8 @@
|
|||||||
<string name="chat_friend">朋友</string>
|
<string name="chat_friend">朋友</string>
|
||||||
|
|
||||||
<string name="agent_chat_list_title">智能体聊天</string>
|
<string name="agent_chat_list_title">智能体聊天</string>
|
||||||
<string name="agent_chat_empty_title">暂无智能体聊天</string>
|
<string name="agent_chat_empty_title">AI 们在等你开启第一句对话</string>
|
||||||
<string name="agent_chat_empty_subtitle">开始与智能体对话吧</string>
|
<string name="agent_chat_empty_subtitle">去首页探索一下,主动发起一场对话!</string>
|
||||||
<string name="agent_chat_me_prefix">我: </string>
|
<string name="agent_chat_me_prefix">我: </string>
|
||||||
<string name="agent_chat_image">[图片]</string>
|
<string name="agent_chat_image">[图片]</string>
|
||||||
<string name="agent_chat_voice">[语音]</string>
|
<string name="agent_chat_voice">[语音]</string>
|
||||||
@@ -159,6 +159,9 @@
|
|||||||
<string name="agent_chat_load_more_failed">加载更多失败</string>
|
<string name="agent_chat_load_more_failed">加载更多失败</string>
|
||||||
<string name="agent_chat_user_info_failed">获取用户信息失败: %s</string>
|
<string name="agent_chat_user_info_failed">获取用户信息失败: %s</string>
|
||||||
|
|
||||||
|
<string name="group_chat_empty_title">没有群聊消息的宇宙太安静了</string>
|
||||||
|
<string name="group_chat_empty_subtitle">在首页探索感兴趣的主题房间</string>
|
||||||
|
|
||||||
<string name="friend_chat_empty_title">暂无朋友聊天</string>
|
<string name="friend_chat_empty_title">暂无朋友聊天</string>
|
||||||
<string name="friend_chat_empty_subtitle">开始与朋友对话吧</string>
|
<string name="friend_chat_empty_subtitle">开始与朋友对话吧</string>
|
||||||
<string name="friend_chat_me_prefix">我: </string>
|
<string name="friend_chat_me_prefix">我: </string>
|
||||||
@@ -167,5 +170,9 @@
|
|||||||
<string name="quick_create">一键创建</string>
|
<string name="quick_create">一键创建</string>
|
||||||
<string name="group_name">群聊名称</string>
|
<string name="group_name">群聊名称</string>
|
||||||
<string name="search_placeholder">搜索</string>
|
<string name="search_placeholder">搜索</string>
|
||||||
|
<string name="group_info_add_other">添加其他人</string>
|
||||||
|
<string name="group_info_notice_setting">通知</string>
|
||||||
|
<string name="group_info_exit">退出</string>
|
||||||
|
<string name="group_info_edit">编辑资料</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -155,6 +155,8 @@
|
|||||||
<string name="agent_chat_load_failed">加载失败</string>
|
<string name="agent_chat_load_failed">加载失败</string>
|
||||||
<string name="agent_chat_load_more_failed">加载更多失败</string>
|
<string name="agent_chat_load_more_failed">加载更多失败</string>
|
||||||
<string name="agent_chat_user_info_failed">获取用户信息失败: %s</string>
|
<string name="agent_chat_user_info_failed">获取用户信息失败: %s</string>
|
||||||
|
<string name="group_chat_empty_title">没有群聊消息的宇宙太安静了</string>
|
||||||
|
<string name="group_chat_empty_subtitle">在首页探索感兴趣的主题房间</string>
|
||||||
<string name="friend_chat_empty_title">暂无朋友聊天</string>
|
<string name="friend_chat_empty_title">暂无朋友聊天</string>
|
||||||
<string name="friend_chat_empty_subtitle">开始与朋友对话吧</string>
|
<string name="friend_chat_empty_subtitle">开始与朋友对话吧</string>
|
||||||
<string name="friend_chat_me_prefix">我: </string>
|
<string name="friend_chat_me_prefix">我: </string>
|
||||||
@@ -163,5 +165,9 @@
|
|||||||
<string name="quick_create">Quick Create</string>
|
<string name="quick_create">Quick Create</string>
|
||||||
<string name="group_name">Group Name</string>
|
<string name="group_name">Group Name</string>
|
||||||
<string name="search_placeholder">Search</string>
|
<string name="search_placeholder">Search</string>
|
||||||
|
<string name="group_info_add_other">添加其他人</string>
|
||||||
|
<string name="group_info_notice_setting">通知</string>
|
||||||
|
<string name="group_info_exit">退出</string>
|
||||||
|
<string name="group_info_edit">编辑资料</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user