From 9fb79b38813152403023b411aeace616c5a9267b Mon Sep 17 00:00:00 2001 From: weber Date: Thu, 21 Aug 2025 19:04:59 +0800 Subject: [PATCH] =?UTF-8?q?=E8=81=8A=E5=A4=A9=E5=AE=A4=E5=92=8C=E7=BE=A4?= =?UTF-8?q?=E8=81=8A=E4=BF=A1=E6=81=AF=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aiosman/ravenow/data/api/RiderProAPI.kt | 2 +- .../java/com/aiosman/ravenow/entity/Group.kt | 1 - .../main/java/com/aiosman/ravenow/ui/Navi.kt | 14 +- .../com/aiosman/ravenow/ui/chat/ChatScreen.kt | 215 ++++++++++-------- .../ravenow/ui/chat/GroupChatScreen.kt | 36 +-- .../ravenow/ui/chat/GroupChatViewModel.kt | 15 -- .../ravenow/ui/group/GroupChatInfoScreen.kt | 132 +++-------- .../ui/group/GroupChatInfoViewModel.kt | 32 ++- app/src/main/res/drawable/group_info_edit.xml | 35 +++ app/src/main/res/drawable/group_info_exit.xml | 25 ++ .../drawable/group_info_notice_setting.xml | 15 ++ .../main/res/drawable/group_info_users.xml | 38 ++++ .../main/res/drawable/rider_pro_add_other.xml | 30 +++ .../res/drawable/rider_pro_notice_mute.xml | 26 ++- .../res/mipmap-xhdpi/rider_pro_im_image.png | Bin 0 -> 1693 bytes app/src/main/res/values-zh/strings.xml | 4 + app/src/main/res/values/strings.xml | 4 + 17 files changed, 362 insertions(+), 262 deletions(-) create mode 100644 app/src/main/res/drawable/group_info_edit.xml create mode 100644 app/src/main/res/drawable/group_info_exit.xml create mode 100644 app/src/main/res/drawable/group_info_notice_setting.xml create mode 100644 app/src/main/res/drawable/group_info_users.xml create mode 100644 app/src/main/res/drawable/rider_pro_add_other.xml create mode 100644 app/src/main/res/mipmap-xhdpi/rider_pro_im_image.png diff --git a/app/src/main/java/com/aiosman/ravenow/data/api/RiderProAPI.kt b/app/src/main/java/com/aiosman/ravenow/data/api/RiderProAPI.kt index 73c516d..d665f50 100644 --- a/app/src/main/java/com/aiosman/ravenow/data/api/RiderProAPI.kt +++ b/app/src/main/java/com/aiosman/ravenow/data/api/RiderProAPI.kt @@ -563,7 +563,7 @@ interface RaveNowAPI { @Query("isRecommended") isRecommended: Int = 1, ): Response> - @GET("rooms/detail") + @GET("outside/rooms/detail") suspend fun getRoomDetail(@Query("trtcId") trtcId: String, ): Response> diff --git a/app/src/main/java/com/aiosman/ravenow/entity/Group.kt b/app/src/main/java/com/aiosman/ravenow/entity/Group.kt index a03c550..fbde97c 100644 --- a/app/src/main/java/com/aiosman/ravenow/entity/Group.kt +++ b/app/src/main/java/com/aiosman/ravenow/entity/Group.kt @@ -12,5 +12,4 @@ data class GroupInfo( val groupName: String, val groupAvatar: String, val memberCount: Int, - val members: List ) \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/ravenow/ui/Navi.kt b/app/src/main/java/com/aiosman/ravenow/ui/Navi.kt index 9a9162c..65b4d40 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/Navi.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/Navi.kt @@ -410,11 +410,12 @@ fun NavigationController( route = NavigationRoute.GroupChatInfo.route, 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( 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( diff --git a/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatScreen.kt index e239a3e..f4c63a1 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/chat/ChatScreen.kt @@ -8,6 +8,7 @@ import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.Crossfade import androidx.compose.animation.core.animateDpAsState +import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -49,6 +50,7 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow import androidx.compose.ui.focus.onFocusChanged @@ -175,7 +177,7 @@ fun ChatScreen(userId: String) { Image( painter = painterResource(R.drawable.rider_pro_back_icon), modifier = Modifier - .size(28.dp) + .size(24.dp) .noRippleClickable { navController.navigateUp() }, @@ -187,8 +189,8 @@ fun ChatScreen(userId: String) { CustomAsyncImage( imageUrl = viewModel.userProfile?.avatar ?: "", modifier = Modifier - .size(40.dp) - .clip(RoundedCornerShape(40.dp)), + .size(32.dp) + .clip(RoundedCornerShape(32.dp)), contentDescription = "avatar" ) Spacer(modifier = Modifier.width(8.dp)) @@ -221,7 +223,7 @@ fun ChatScreen(userId: String) { }, menuItems = listOf( 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, ) { @@ -251,8 +253,7 @@ fun ChatScreen(userId: String) { modifier = Modifier .fillMaxWidth() .height(1.dp) - .background( - AppColors.decentBackground) + ) Spacer(modifier = Modifier.height(8.dp)) ChatInput( @@ -270,13 +271,12 @@ fun ChatScreen(userId: String) { Box( modifier = Modifier .fillMaxSize() - .background(AppColors.decentBackground) + .background(AppColors.background) .padding(paddingValues) ) { LazyColumn( state = listState, - modifier = Modifier - .fillMaxSize(), + modifier = Modifier.fillMaxSize(), reverseLayout = true, verticalArrangement = Arrangement.Top ) { @@ -340,6 +340,7 @@ fun ChatScreen(userId: String) { @Composable fun ChatSelfItem(item: ChatItem) { + val context = LocalContext.current Column( modifier = Modifier @@ -353,19 +354,28 @@ fun ChatSelfItem(item: ChatItem) { Column( 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( modifier = Modifier .widthIn( min = 20.dp, max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp) ) - .clip(RoundedCornerShape(8.dp)) - .background(Color(0xFF000000)) + .clip(RoundedCornerShape(20.dp)) + .background(Color(0xFF6246FF)) .padding( 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) ) - .padding(bottom = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 3.dp else 0.dp)) + ) { when (item.messageType) { V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> { @@ -373,7 +383,7 @@ fun ChatSelfItem(item: ChatItem) { text = item.message, style = TextStyle( color = Color.White, - fontSize = 16.sp, + fontSize = 14.sp, ), textAlign = TextAlign.Start ) @@ -389,28 +399,28 @@ fun ChatSelfItem(item: ChatItem) { else -> { Text( - text = "Unsupported message type", + text = "不支持的消息类型", style = TextStyle( color = Color.White, - fontSize = 16.sp, + fontSize = 14.sp, ) ) } } } } - Spacer(modifier = Modifier.width(12.dp)) + /*Spacer(modifier = Modifier.width(12.dp)) Box( modifier = Modifier - .size(40.dp) - .clip(RoundedCornerShape(40.dp)) + .size(24.dp) + .clip(RoundedCornerShape(24.dp)) ) { CustomAsyncImage( imageUrl = item.avatar, modifier = Modifier.fillMaxSize(), contentDescription = "avatar" ) - } + }*/ } } } @@ -430,11 +440,11 @@ fun ChatOtherItem(item: ChatItem) { ) { Box( modifier = Modifier - .size(40.dp) - .clip(RoundedCornerShape(40.dp)) + .size(24.dp) + .clip(RoundedCornerShape(24.dp)) ) { CustomAsyncImage( - imageUrl = item.avatar, + imageUrl = item.avatar.replace("storage/avatars/", "/avatar/"), modifier = Modifier.fillMaxSize(), contentDescription = "avatar" ) @@ -447,13 +457,12 @@ fun ChatOtherItem(item: ChatItem) { min = 20.dp, max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp) ) - .clip(RoundedCornerShape(8.dp)) - .background(AppColors.background) + .clip(RoundedCornerShape(20.dp)) + .background(AppColors.bubbleBackground) .padding( 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) ) - .padding(bottom = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 3.dp else 0.dp)) ) { when (item.messageType) { V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> { @@ -461,7 +470,7 @@ fun ChatOtherItem(item: ChatItem) { text = item.message, style = TextStyle( color = AppColors.text, - fontSize = 16.sp, + fontSize = 14.sp, ), textAlign = TextAlign.Start ) @@ -477,7 +486,7 @@ fun ChatOtherItem(item: ChatItem) { else -> { Text( - text = "Unsupported message type", + text = "不支持的消息类型", style = TextStyle( color = AppColors.text, fontSize = 16.sp, @@ -486,7 +495,6 @@ fun ChatOtherItem(item: ChatItem) { } } } - } } @@ -547,89 +555,96 @@ fun ChatInput( onSendImage(uri) } } + Box( modifier = Modifier + .fillMaxWidth() + .padding(start = 16.dp, end = 16.dp, bottom = 12.dp),){ - Row( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp) - .padding(bottom = inputBarHeight) - ) { - Box( + Row( modifier = Modifier - .weight(1f) - .clip(RoundedCornerShape(16.dp)) - .background(appColors.background) - .padding(horizontal = 16.dp), - contentAlignment = Alignment.CenterStart, + .fillMaxWidth() + .clip(RoundedCornerShape(20.dp)) + .background(appColors.decentBackground) + .padding(start = 16.dp, end = 8.dp, top = 2.dp, bottom = 2.dp), + verticalAlignment = Alignment.CenterVertically, ) { - BasicTextField( - value = text, - onValueChange = { - text = it - }, - textStyle = TextStyle( - color = appColors.text, - fontSize = 16.sp - ), - cursorBrush = SolidColor(appColors.text), + Box( modifier = Modifier - .fillMaxWidth() - .padding(vertical = 8.dp) - .onFocusChanged { focusState -> - isKeyboardOpen = focusState.isFocused - } - .pointerInput(Unit) { - awaitPointerEventScope { - keyboardController = softwareKeyboardController - awaitFirstDown().also { - keyboardController?.show() + .weight(1f) + ) { + BasicTextField( + value = text, + onValueChange = { + text = it + }, + textStyle = TextStyle( + color = appColors.text, + fontSize = 16.sp + ), + cursorBrush = SolidColor(appColors.text), + singleLine = true, + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp) + .onFocusChanged { focusState -> + isKeyboardOpen = focusState.isFocused + } + .pointerInput(Unit) { + awaitPointerEventScope { + keyboardController = softwareKeyboardController + awaitFirstDown().also { + keyboardController?.show() + } } + }, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), + keyboardActions = KeyboardActions( + onDone = { + keyboardController?.hide() } - }, - keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), - keyboardActions = KeyboardActions( - onDone = { - keyboardController?.hide() - } - ) - ) - } - Spacer(modifier = Modifier.width(16.dp)) - Icon( - painter = painterResource(id = R.drawable.rider_pro_camera), - contentDescription = "Emoji", - modifier = Modifier - .size(30.dp) - .noRippleClickable { - imagePickUpLauncher.launch( - Intent.createChooser( - Intent(Intent.ACTION_GET_CONTENT).apply { - type = "image/*" - }, - "Select Image" - ) ) - }, - tint = appColors.chatActionColor - ) - Spacer(modifier = Modifier.width(8.dp)) - Crossfade( - targetState = text.isNotEmpty(), animationSpec = tween(500), - label = "" - ) { isNotEmpty -> - Icon( - painter = painterResource(id = R.drawable.rider_pro_video_share), - contentDescription = "Emoji", + ) + } + Spacer(modifier = Modifier.width(8.dp)) + Image( + painter = painterResource(R.mipmap.rider_pro_im_image), + contentDescription = "Image", modifier = Modifier - .size(32.dp) + .size(30.dp) .noRippleClickable { - if (text.isNotEmpty()) { - onSend(text) - text = "" - } + imagePickUpLauncher.launch( + Intent.createChooser( + Intent(Intent.ACTION_GET_CONTENT).apply { + type = "image/*" + }, + "Select Image" + ) + ) }, - tint = if (isNotEmpty) appColors.main else appColors.chatActionColor ) + + Spacer(modifier = Modifier.width(8.dp)) + Crossfade( + targetState = text.isNotEmpty(), animationSpec = tween(500), + label = "" + ) { isNotEmpty -> + val alpha by animateFloatAsState( + targetValue = if (isNotEmpty) 1f else 0.5f, + animationSpec = tween(300) + ) + Image( + painter = painterResource(R.mipmap.rider_pro_im_send), + modifier = Modifier + .size(24.dp) + .alpha(alpha) + .noRippleClickable { + if (text.isNotEmpty()) { + onSend(text) + text = "" + } + }, + contentDescription = null, + ) + } } } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/chat/GroupChatScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/chat/GroupChatScreen.kt index ffea47b..25692c1 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/chat/GroupChatScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/chat/GroupChatScreen.kt @@ -191,7 +191,7 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) { } else { Box( modifier = Modifier - .size(40.dp) + .size(24.dp) .clip(RoundedCornerShape(8.dp)) .background(AppColors.decentBackground), contentAlignment = Alignment.Center @@ -231,40 +231,11 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) { modifier = Modifier .size(28.dp) .noRippleClickable { - // 跳转到群聊信息页面 - navController.navigate("GroupChatInfo/$groupId") + isMenuExpanded = true }, contentDescription = null, 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( horizontalArrangement = Arrangement.Start, - verticalAlignment = Alignment.Bottom, modifier = Modifier.fillMaxWidth() ) { if (showAvatarAndNickname) { @@ -534,7 +504,7 @@ fun GroupChatOtherItem(item: ChatItem, showAvatarAndNickname: Boolean = true) { color = AppColors.secondaryText, fontSize = 12.sp, ), - modifier = Modifier.padding(top = 2.dp) + modifier = Modifier.padding(bottom = 2.dp) ) } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/chat/GroupChatViewModel.kt b/app/src/main/java/com/aiosman/ravenow/ui/chat/GroupChatViewModel.kt index 7d3633e..4274a74 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/chat/GroupChatViewModel.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/chat/GroupChatViewModel.kt @@ -48,7 +48,6 @@ class GroupChatViewModel( var isLoading by mutableStateOf(false) var lastMessage: V2TIMMessage? = null val showTimestampMap = mutableMapOf() - var chatNotification by mutableStateOf(null) var goToNew by mutableStateOf(false) // 群聊特有属性 @@ -71,8 +70,6 @@ class GroupChatViewModel( myProfile = accountService.getMyAccountProfile() RegistListener(context) fetchHistoryMessage(context) - val notiStrategy = ChatState.getStrategyByTargetTrtcId(groupId) - chatNotification = notiStrategy } catch (e: Exception) { Log.e("GroupChatViewModel", "初始化失败: ${e.message}") } @@ -287,16 +284,4 @@ class GroupChatViewModel( 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", "获取群成员功能待实现") - } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt index 8f2dc2d..5a360df 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoScreen.kt @@ -16,7 +16,9 @@ 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 @@ -76,10 +78,11 @@ fun GroupChatInfoScreen(groupId: String) { Spacer(modifier = Modifier.width(16.dp)) Text( modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Start, text = "群聊信息", style = androidx.compose.ui.text.TextStyle( color = AppColors.text, - fontSize = 18.sp, + fontSize = 17.sp, fontWeight = FontWeight.Bold ) @@ -104,7 +107,7 @@ fun GroupChatInfoScreen(groupId: String) { imageUrl = viewModel.groupInfo!!.groupAvatar, modifier = Modifier .size(80.dp) - .clip(CircleShape), + .clip(RoundedCornerShape(12.dp)), contentDescription = "群聊头像" ) } else { @@ -136,19 +139,6 @@ fun GroupChatInfoScreen(groupId: String) { 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( modifier = Modifier .size(48.dp) - .clip(CircleShape) - .background(Color(0xFF007AFF)), + .clip(CircleShape), contentAlignment = Alignment.Center ) { Image( - painter = painterResource(R.drawable.rider_pro_back_icon), + painter = painterResource(R.drawable.rider_pro_add_other), modifier = Modifier.size(24.dp), contentDescription = null, - colorFilter = ColorFilter.tint(Color.White) + colorFilter = ColorFilter.tint( + AppColors.text) ) } Spacer(modifier = Modifier.height(8.dp)) Text( - text = "添加其他人", + text = stringResource(R.string.group_info_add_other), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 12.sp @@ -194,26 +184,30 @@ fun GroupChatInfoScreen(groupId: String) { Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.noRippleClickable { - // TODO: 实现通知设置功能 + /* if (viewModel.notificationStrategy == "mute") { + viewModel.updateNotificationStrategy("active") + } else { + viewModel.updateNotificationStrategy("mute") + }*/ } ) { Box( modifier = Modifier .size(48.dp) - .clip(CircleShape) - .background(Color(0xFF007AFF)), + .clip(CircleShape), contentAlignment = Alignment.Center ) { 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), contentDescription = null, - colorFilter = ColorFilter.tint(Color.White) + colorFilter = ColorFilter.tint( + AppColors.text) ) } Spacer(modifier = Modifier.height(8.dp)) Text( - text = "通知", + text = stringResource(R.string.group_info_notice_setting), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 12.sp @@ -231,20 +225,21 @@ fun GroupChatInfoScreen(groupId: String) { Box( modifier = Modifier .size(48.dp) - .clip(CircleShape) - .background(Color(0xFFFF3B30)), + .clip(CircleShape), contentAlignment = Alignment.Center ) { Image( - painter = painterResource(R.drawable.rider_pro_back_icon), + painter = painterResource(R.drawable.group_info_exit + ), modifier = Modifier.size(24.dp), contentDescription = null, - colorFilter = ColorFilter.tint(Color.White) + colorFilter = ColorFilter.tint( + AppColors.text) ) } Spacer(modifier = Modifier.height(8.dp)) Text( - text = "退出", + text = stringResource(R.string.group_info_exit), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 12.sp @@ -263,7 +258,6 @@ fun GroupChatInfoScreen(groupId: String) { modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(8.dp)) - .background(AppColors.decentBackground) .padding(16.dp) .noRippleClickable { // TODO: 实现设置聊天主题功能 @@ -271,14 +265,15 @@ fun GroupChatInfoScreen(groupId: String) { verticalAlignment = Alignment.CenterVertically ) { Image( - painter = painterResource(R.drawable.rider_pro_back_icon), + painter = painterResource(R.drawable.group_info_edit), modifier = Modifier.size(24.dp), contentDescription = null, - colorFilter = ColorFilter.tint(AppColors.text) + colorFilter = ColorFilter.tint( + AppColors.text) ) Spacer(modifier = Modifier.width(12.dp)) Text( - text = "设置聊天主题", + text = stringResource(R.string.group_info_edit), style = androidx.compose.ui.text.TextStyle( color = AppColors.text, fontSize = 16.sp @@ -286,10 +281,9 @@ fun GroupChatInfoScreen(groupId: String) { modifier = Modifier.weight(1f) ) Image( - painter = painterResource(R.drawable.rider_pro_back_icon), - modifier = Modifier.size(16.dp), + painter = painterResource(R.drawable.rave_now_nav_right), + modifier = Modifier.size(18.dp), contentDescription = null, - colorFilter = ColorFilter.tint(AppColors.secondaryText) ) } @@ -300,7 +294,6 @@ fun GroupChatInfoScreen(groupId: String) { modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(8.dp)) - .background(AppColors.decentBackground) .padding(16.dp) .noRippleClickable { // TODO: 实现查看群聊成员功能 @@ -308,10 +301,11 @@ fun GroupChatInfoScreen(groupId: String) { verticalAlignment = Alignment.CenterVertically ) { Image( - painter = painterResource(R.drawable.rider_pro_back_icon), + painter = painterResource(R.drawable.group_info_users), modifier = Modifier.size(24.dp), contentDescription = null, - colorFilter = ColorFilter.tint(AppColors.text) + colorFilter = ColorFilter.tint( + AppColors.text) ) Spacer(modifier = Modifier.width(12.dp)) Text( @@ -323,64 +317,12 @@ fun GroupChatInfoScreen(groupId: String) { modifier = Modifier.weight(1f) ) Image( - painter = painterResource(R.drawable.rider_pro_back_icon), - modifier = Modifier.size(16.dp), + painter = painterResource(R.drawable.rave_now_nav_right), + modifier = Modifier.size(18.dp), 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 - ) - ) - } - } - } - } - } } } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoViewModel.kt b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoViewModel.kt index e28d0ec..1fc5289 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoViewModel.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/group/GroupChatInfoViewModel.kt @@ -5,7 +5,10 @@ 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 @@ -17,13 +20,21 @@ class GroupChatInfoViewModel( var groupInfo by mutableStateOf(null) var isLoading by mutableStateOf(false) var error by mutableStateOf(null) - + var chatNotification by mutableStateOf(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 @@ -37,16 +48,17 @@ class GroupChatInfoViewModel( GroupInfo( groupId = groupId, groupName = it.name, - groupAvatar = room.avatar, - memberCount = room.userCount, - members = listOf( - GroupMember( - userId = room.creator.userId, - nickname = room.creator.profile.nickname, - avatar = room.creator.profile.avatar, - isOwner = true + 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, ) } diff --git a/app/src/main/res/drawable/group_info_edit.xml b/app/src/main/res/drawable/group_info_edit.xml new file mode 100644 index 0000000..fee041b --- /dev/null +++ b/app/src/main/res/drawable/group_info_edit.xml @@ -0,0 +1,35 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/group_info_exit.xml b/app/src/main/res/drawable/group_info_exit.xml new file mode 100644 index 0000000..efc4b16 --- /dev/null +++ b/app/src/main/res/drawable/group_info_exit.xml @@ -0,0 +1,25 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/group_info_notice_setting.xml b/app/src/main/res/drawable/group_info_notice_setting.xml new file mode 100644 index 0000000..628020e --- /dev/null +++ b/app/src/main/res/drawable/group_info_notice_setting.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/group_info_users.xml b/app/src/main/res/drawable/group_info_users.xml new file mode 100644 index 0000000..2ccb738 --- /dev/null +++ b/app/src/main/res/drawable/group_info_users.xml @@ -0,0 +1,38 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rider_pro_add_other.xml b/app/src/main/res/drawable/rider_pro_add_other.xml new file mode 100644 index 0000000..4c303e7 --- /dev/null +++ b/app/src/main/res/drawable/rider_pro_add_other.xml @@ -0,0 +1,30 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rider_pro_notice_mute.xml b/app/src/main/res/drawable/rider_pro_notice_mute.xml index bfbc214..24d57e9 100644 --- a/app/src/main/res/drawable/rider_pro_notice_mute.xml +++ b/app/src/main/res/drawable/rider_pro_notice_mute.xml @@ -1,5 +1,21 @@ - - - - - + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-xhdpi/rider_pro_im_image.png b/app/src/main/res/mipmap-xhdpi/rider_pro_im_image.png new file mode 100644 index 0000000000000000000000000000000000000000..2036acecb8c2cd1270a7105ee6e41ec75e9c6749 GIT binary patch literal 1693 zcmV;O24eY%P)XTEo z-N(8c$O5Sen!x~(h@@01K87sHiY%aE%x%oaV^}P5kjsQCOo+hRicZmM79~`~DzcSb z$4Cd&Mb+;W!;0s*3nU0EU;^9nx$Qj(Xm4*1Xl+_OR*|o)+bRxmzyc<)QNtm8ncI~B zN~uUcrggPqZ54_wLnz?{*riQ3>$2s^I;p4dQwx~>a_0Ltm(wHXJ_B~Kw+0l0KhlT?)_XVuN% z0#0^?a|BTK=g}V4s=0c*j0a!?7jOc%?D9DR$ULdR{YTc=!8tK**|e4k;Ll*+Dn4zp z**MJ^H_kC5Zb<+oR8(}OGQ(Gv;lRk?=AZk2Z#&m_{^Ys7-@f?e^2MVAe_wsVZ82~J zS1W!=K&&Gc;Frnrl%YRAczrWn<~p*@_u;i#$%e6det6S5R=Ko;m~BL#@@f&dY`KRD;Gd1m7xrVa<%#Be5=5Y z{P==2IWygo-~Yb{T)`O@E6WUgr73fjxiR7#aYCM1>e?Mo-*|nf;i^{ z?H7HHF%||mgS*&GyH~uQx4_)=bv1Q;COh)SntIbijf469xgKyAW3kw(2xxw4!-OpR z&*svA#WVte%J0@Ut&d{nwt>4C)Pg>@3B|_kX?fwt+N$6gK_KIVm^#B#eLml{+S;1l zUCrD2+1%3!?jpOFTng}noi}*kBp7Y(zyk6j(7I6FVMi(RzKvj9B4X6B=Z2@y*2 z5@e6wH|8R9p0U7P6o_E5d&!fCE7ym18pL${8Au!s(-a!7-@fVTYJxMk^Y?%nP&J1d zOYYnErUD67eSOJLqCrwu58S#F4!VW2ICBB)>qgU5&2*DIJ^Akj{Q2C(dW@0pM#7ui zwdP9#U^spHbdsdWBF1a7F>ah=2DxPdxV?@iVP}$9OF?Z~-SfF17*? zNWY;fnI$o($NWJwUYl{?T=EdeD**9G)JOFNe*eMXwv`|bHBlQJ3c(c=fJ9t6xskoR z*b@NrRcWjiYNEDNJx2impp+W)YdRk>B5|w?Y~^UcMh(=Wtfre9t^`;>cm~V8@?1=a zxq53`c}_iu0~6S&;S`_g_ap#`l)bTgdV1m~dr#gY)g*>(E$l04JeOer3z)$6isM;8 zMgfyjs&;k##(X@cnnaO一键创建 群聊名称 搜索 + 添加其他人 + 通知 + 退出 + 编辑资料 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d66cf46..70e5967 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -165,5 +165,9 @@ Quick Create Group Name Search + 添加其他人 + 通知 + 退出 + 编辑资料 \ No newline at end of file