聊天室和群聊信息调整

This commit is contained in:
weber
2025-08-21 19:04:59 +08:00
parent 5ee1897739
commit 9fb79b3881
17 changed files with 362 additions and 262 deletions

View File

@@ -563,7 +563,7 @@ interface RaveNowAPI {
@Query("isRecommended") isRecommended: Int = 1, @Query("isRecommended") isRecommended: Int = 1,
): Response<ListContainer<Room>> ): Response<ListContainer<Room>>
@GET("rooms/detail") @GET("outside/rooms/detail")
suspend fun getRoomDetail(@Query("trtcId") trtcId: String, suspend fun getRoomDetail(@Query("trtcId") trtcId: String,
): Response<DataContainer<Room>> ): Response<DataContainer<Room>>

View File

@@ -12,5 +12,4 @@ data class GroupInfo(
val groupName: String, val groupName: String,
val groupAvatar: String, val groupAvatar: String,
val memberCount: Int, val memberCount: Int,
val members: List<GroupMember>
) )

View File

@@ -410,11 +410,12 @@ fun NavigationController(
route = NavigationRoute.GroupChatInfo.route, route = NavigationRoute.GroupChatInfo.route,
arguments = listOf(navArgument("groupId") { type = NavType.StringType }) arguments = listOf(navArgument("groupId") { type = NavType.StringType })
) { ) {
val groupId = it.arguments?.getString("groupId") ?: "" val encodedId = it.arguments?.getString("groupId")
val decodedId = encodedId?.let { java.net.URLDecoder.decode(it, "UTF-8") }
CompositionLocalProvider( CompositionLocalProvider(
LocalAnimatedContentScope provides this, LocalAnimatedContentScope provides this,
) { ) {
GroupChatInfoScreen(groupId) GroupChatInfoScreen(decodedId?:"")
} }
} }
@@ -528,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(

View File

@@ -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> {

View File

@@ -191,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
@@ -231,40 +231,11 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) {
modifier = Modifier modifier = Modifier
.size(28.dp) .size(28.dp)
.noRippleClickable { .noRippleClickable {
// 跳转到群聊信息页面 isMenuExpanded = true
navController.navigate("GroupChatInfo/$groupId")
}, },
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()
}
),
)
} }
} }
} }
@@ -461,7 +432,6 @@ fun GroupChatOtherItem(item: ChatItem, showAvatarAndNickname: Boolean = true) {
) { ) {
Row( Row(
horizontalArrangement = Arrangement.Start, horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.Bottom,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
if (showAvatarAndNickname) { if (showAvatarAndNickname) {
@@ -534,7 +504,7 @@ fun GroupChatOtherItem(item: ChatItem, showAvatarAndNickname: Boolean = true) {
color = AppColors.secondaryText, color = AppColors.secondaryText,
fontSize = 12.sp, fontSize = 12.sp,
), ),
modifier = Modifier.padding(top = 2.dp) modifier = Modifier.padding(bottom = 2.dp)
) )
} }
} }

View File

@@ -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", "获取群成员功能待实现")
}
} }

View File

@@ -16,7 +16,9 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter 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.res.painterResource
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.TextAlign
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.lifecycle.ViewModel import androidx.lifecycle.ViewModel
@@ -76,10 +78,11 @@ fun GroupChatInfoScreen(groupId: String) {
Spacer(modifier = Modifier.width(16.dp)) Spacer(modifier = Modifier.width(16.dp))
Text( Text(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Start,
text = "群聊信息", text = "群聊信息",
style = androidx.compose.ui.text.TextStyle( style = androidx.compose.ui.text.TextStyle(
color = AppColors.text, color = AppColors.text,
fontSize = 18.sp, fontSize = 17.sp,
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold
) )
@@ -104,7 +107,7 @@ fun GroupChatInfoScreen(groupId: String) {
imageUrl = viewModel.groupInfo!!.groupAvatar, imageUrl = viewModel.groupInfo!!.groupAvatar,
modifier = Modifier modifier = Modifier
.size(80.dp) .size(80.dp)
.clip(CircleShape), .clip(RoundedCornerShape(12.dp)),
contentDescription = "群聊头像" contentDescription = "群聊头像"
) )
} else { } else {
@@ -136,19 +139,6 @@ fun GroupChatInfoScreen(groupId: String) {
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold
) )
) )
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "更改名称和图片",
style = androidx.compose.ui.text.TextStyle(
color = Color(0xFF007AFF),
fontSize = 14.sp
),
modifier = Modifier.noRippleClickable {
// TODO: 实现更改群聊名称和图片功能
}
)
} }
} }
@@ -169,20 +159,20 @@ fun GroupChatInfoScreen(groupId: String) {
Box( Box(
modifier = Modifier modifier = Modifier
.size(48.dp) .size(48.dp)
.clip(CircleShape) .clip(CircleShape),
.background(Color(0xFF007AFF)),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Image( Image(
painter = painterResource(R.drawable.rider_pro_back_icon), painter = painterResource(R.drawable.rider_pro_add_other),
modifier = Modifier.size(24.dp), modifier = Modifier.size(24.dp),
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint(Color.White) colorFilter = ColorFilter.tint(
AppColors.text)
) )
} }
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text( Text(
text = "添加其他人", text = stringResource(R.string.group_info_add_other),
style = androidx.compose.ui.text.TextStyle( style = androidx.compose.ui.text.TextStyle(
color = AppColors.text, color = AppColors.text,
fontSize = 12.sp fontSize = 12.sp
@@ -194,26 +184,30 @@ fun GroupChatInfoScreen(groupId: String) {
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.noRippleClickable { modifier = Modifier.noRippleClickable {
// TODO: 实现通知设置功能 /* if (viewModel.notificationStrategy == "mute") {
viewModel.updateNotificationStrategy("active")
} else {
viewModel.updateNotificationStrategy("mute")
}*/
} }
) { ) {
Box( Box(
modifier = Modifier modifier = Modifier
.size(48.dp) .size(48.dp)
.clip(CircleShape) .clip(CircleShape),
.background(Color(0xFF007AFF)),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Image( Image(
painter = painterResource(R.drawable.rider_pro_notice_active), painter = painterResource(if (viewModel.notificationStrategy == "mute") R.drawable.rider_pro_notice_mute else R.drawable.rider_pro_notice_active,),
modifier = Modifier.size(24.dp), modifier = Modifier.size(24.dp),
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint(Color.White) colorFilter = ColorFilter.tint(
AppColors.text)
) )
} }
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text( Text(
text = "通知", text = stringResource(R.string.group_info_notice_setting),
style = androidx.compose.ui.text.TextStyle( style = androidx.compose.ui.text.TextStyle(
color = AppColors.text, color = AppColors.text,
fontSize = 12.sp fontSize = 12.sp
@@ -231,20 +225,21 @@ fun GroupChatInfoScreen(groupId: String) {
Box( Box(
modifier = Modifier modifier = Modifier
.size(48.dp) .size(48.dp)
.clip(CircleShape) .clip(CircleShape),
.background(Color(0xFFFF3B30)),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Image( Image(
painter = painterResource(R.drawable.rider_pro_back_icon), painter = painterResource(R.drawable.group_info_exit
),
modifier = Modifier.size(24.dp), modifier = Modifier.size(24.dp),
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint(Color.White) colorFilter = ColorFilter.tint(
AppColors.text)
) )
} }
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text( Text(
text = "退出", text = stringResource(R.string.group_info_exit),
style = androidx.compose.ui.text.TextStyle( style = androidx.compose.ui.text.TextStyle(
color = AppColors.text, color = AppColors.text,
fontSize = 12.sp fontSize = 12.sp
@@ -263,7 +258,6 @@ fun GroupChatInfoScreen(groupId: String) {
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(8.dp)) .clip(RoundedCornerShape(8.dp))
.background(AppColors.decentBackground)
.padding(16.dp) .padding(16.dp)
.noRippleClickable { .noRippleClickable {
// TODO: 实现设置聊天主题功能 // TODO: 实现设置聊天主题功能
@@ -271,14 +265,15 @@ fun GroupChatInfoScreen(groupId: String) {
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Image( Image(
painter = painterResource(R.drawable.rider_pro_back_icon), painter = painterResource(R.drawable.group_info_edit),
modifier = Modifier.size(24.dp), modifier = Modifier.size(24.dp),
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint(AppColors.text) colorFilter = ColorFilter.tint(
AppColors.text)
) )
Spacer(modifier = Modifier.width(12.dp)) Spacer(modifier = Modifier.width(12.dp))
Text( Text(
text = "设置聊天主题", text = stringResource(R.string.group_info_edit),
style = androidx.compose.ui.text.TextStyle( style = androidx.compose.ui.text.TextStyle(
color = AppColors.text, color = AppColors.text,
fontSize = 16.sp fontSize = 16.sp
@@ -286,10 +281,9 @@ fun GroupChatInfoScreen(groupId: String) {
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) )
Image( Image(
painter = painterResource(R.drawable.rider_pro_back_icon), painter = painterResource(R.drawable.rave_now_nav_right),
modifier = Modifier.size(16.dp), modifier = Modifier.size(18.dp),
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint(AppColors.secondaryText)
) )
} }
@@ -300,7 +294,6 @@ fun GroupChatInfoScreen(groupId: String) {
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(8.dp)) .clip(RoundedCornerShape(8.dp))
.background(AppColors.decentBackground)
.padding(16.dp) .padding(16.dp)
.noRippleClickable { .noRippleClickable {
// TODO: 实现查看群聊成员功能 // TODO: 实现查看群聊成员功能
@@ -308,10 +301,11 @@ fun GroupChatInfoScreen(groupId: String) {
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Image( Image(
painter = painterResource(R.drawable.rider_pro_back_icon), painter = painterResource(R.drawable.group_info_users),
modifier = Modifier.size(24.dp), modifier = Modifier.size(24.dp),
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint(AppColors.text) colorFilter = ColorFilter.tint(
AppColors.text)
) )
Spacer(modifier = Modifier.width(12.dp)) Spacer(modifier = Modifier.width(12.dp))
Text( Text(
@@ -323,64 +317,12 @@ fun GroupChatInfoScreen(groupId: String) {
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) )
Image( Image(
painter = painterResource(R.drawable.rider_pro_back_icon), painter = painterResource(R.drawable.rave_now_nav_right),
modifier = Modifier.size(16.dp), modifier = Modifier.size(18.dp),
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint(AppColors.secondaryText)
) )
} }
} }
// 成员列表
if (viewModel.groupInfo?.members?.isNotEmpty() == true) {
item {
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "群成员",
style = androidx.compose.ui.text.TextStyle(
color = AppColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.Bold
)
)
}
items(viewModel.groupInfo!!.members) { member ->
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
CustomAsyncImage(
imageUrl = member.avatar,
modifier = Modifier
.size(40.dp)
.clip(CircleShape),
contentDescription = "成员头像"
)
Spacer(modifier = Modifier.width(12.dp))
Column {
Text(
text = member.nickname,
style = androidx.compose.ui.text.TextStyle(
color = AppColors.text,
fontSize = 16.sp
)
)
if (member.isOwner) {
Text(
text = "群主",
style = androidx.compose.ui.text.TextStyle(
color = AppColors.secondaryText,
fontSize = 12.sp
)
)
}
}
}
}
}
} }
} }
} }

View File

@@ -5,7 +5,10 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope 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.data.api.ApiClient
import com.aiosman.ravenow.entity.ChatNotification
import com.aiosman.ravenow.entity.GroupInfo import com.aiosman.ravenow.entity.GroupInfo
import com.aiosman.ravenow.entity.GroupMember import com.aiosman.ravenow.entity.GroupMember
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -17,13 +20,21 @@ class GroupChatInfoViewModel(
var groupInfo by mutableStateOf<GroupInfo?>(null) var groupInfo by mutableStateOf<GroupInfo?>(null)
var isLoading by mutableStateOf(false) var isLoading by mutableStateOf(false)
var error by mutableStateOf<String?>(null) var error by mutableStateOf<String?>(null)
var chatNotification by mutableStateOf<ChatNotification?>(null)
val notificationStrategy get() = chatNotification?.strategy ?: "default"
init { init {
loadGroupInfo() loadGroupInfo()
} }
suspend fun updateNotificationStrategy(strategy: String) {
val result = ChatState.updateChatNotification(groupId.hashCode(), strategy)
chatNotification = result
}
private fun loadGroupInfo() { private fun loadGroupInfo() {
viewModelScope.launch { viewModelScope.launch {
val notiStrategy = ChatState.getStrategyByTargetTrtcId(groupId)
chatNotification = notiStrategy
try { try {
isLoading = true isLoading = true
error = null error = null
@@ -37,16 +48,17 @@ class GroupChatInfoViewModel(
GroupInfo( GroupInfo(
groupId = groupId, groupId = groupId,
groupName = it.name, groupName = it.name,
groupAvatar = room.avatar, 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, memberCount = room.userCount,
members = listOf(
GroupMember(
userId = room.creator.userId,
nickname = room.creator.profile.nickname,
avatar = room.creator.profile.avatar,
isOwner = true
)
)
) )
} }

View 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>

View 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>

View 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>

View 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>

View 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>

View File

@@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -170,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>

View File

@@ -165,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>