From 4aae854b786a2c5daea5318f07f36aed7d5e46df Mon Sep 17 00:00:00 2001 From: roxy Date: Sat, 9 May 2026 16:12:15 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A2=86=E5=8F=96=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/app/constants/sc_room_msg_type.dart | 3 + lib/services/audio/rtc_manager.dart | 30 +++++++++ lib/services/audio/rtm_manager.dart | 10 +++ .../room_red_packet_open_dialog.dart | 18 +++--- lib/ui_kit/widgets/room/room_msg_item.dart | 62 +++++++++++++++++++ 需求进度.md | 1 + 6 files changed, 113 insertions(+), 11 deletions(-) diff --git a/lib/app/constants/sc_room_msg_type.dart b/lib/app/constants/sc_room_msg_type.dart index 9b60dc4..eacc5e3 100644 --- a/lib/app/constants/sc_room_msg_type.dart +++ b/lib/app/constants/sc_room_msg_type.dart @@ -70,6 +70,9 @@ class SCRoomMsgType { ///房间红包 static const String roomRedPacket = "ROOM_RED_PACKET"; + ///房间红包领取通知 + static const String roomRedPacketClaim = "ROOM_RED_PACKET_CLAIM"; + ///邀请进入房间 static const String inviteRoom = "INVITE_ROOM"; diff --git a/lib/services/audio/rtc_manager.dart b/lib/services/audio/rtc_manager.dart index 75cc4b3..378a646 100644 --- a/lib/services/audio/rtc_manager.dart +++ b/lib/services/audio/rtc_manager.dart @@ -3022,6 +3022,36 @@ class RealTimeCommunicationManager extends ChangeNotifier { ); } + void sendRoomRedPacketClaimMessage({ + required String packetId, + required num amount, + required String packetSenderName, + }) { + final groupId = currenRoom?.roomProfile?.roomProfile?.roomAccount ?? ""; + if (groupId.isEmpty) { + return; + } + final normalizedPacketId = packetId.trim(); + final normalizedSenderName = packetSenderName.trim(); + unawaited( + rtmProvider?.dispatchMessage( + Msg( + groupId: groupId, + msg: normalizedSenderName, + type: SCRoomMsgType.roomRedPacketClaim, + role: currenRoom?.entrants?.roles ?? "", + number: amount, + giftBatchId: + normalizedPacketId.isEmpty + ? null + : 'room-red-packet-claim-$normalizedPacketId', + user: AccountStorage().getCurrentUser()?.userProfile, + ), + ) ?? + Future.value(), + ); + } + void _refreshRoomRedPacketListAfterEntry() { final roomId = currenRoom?.roomProfile?.roomProfile?.id?.trim() ?? ""; if (roomId.isEmpty) { diff --git a/lib/services/audio/rtm_manager.dart b/lib/services/audio/rtm_manager.dart index 1d0c599..833a710 100644 --- a/lib/services/audio/rtm_manager.dart +++ b/lib/services/audio/rtm_manager.dart @@ -753,6 +753,7 @@ class RealTimeMessagingManager extends ChangeNotifier { case SCRoomMsgType.roomGameClose: case SCRoomMsgType.roomGameCreate: case SCRoomMsgType.luckGiftAnimOther: + case SCRoomMsgType.roomRedPacketClaim: _sendRoomMessage(msg); break; default: @@ -1133,6 +1134,8 @@ class RealTimeMessagingManager extends ChangeNotifier { case SCRoomMsgType.text: case SCRoomMsgType.image: return true; + case SCRoomMsgType.roomRedPacketClaim: + return true; case SCRoomMsgType.emoticons: return (msg.number ?? -1) < 0; default: @@ -1191,6 +1194,13 @@ class RealTimeMessagingManager extends ChangeNotifier { roomChatMsgList.removeAt(roomChatMsgList.length - 1); } msgChatListener?.call(msg); + } else if (msg.type == SCRoomMsgType.roomRedPacketClaim) { + roomChatMsgList.insert(0, msg); + if (roomChatMsgList.length > 250) { + print('大于200条消息'); + roomChatMsgList.removeAt(roomChatMsgList.length - 1); + } + msgChatListener?.call(msg); } else if (msg.type == SCRoomMsgType.gift || msg.type == SCRoomMsgType.luckGiftAnimOther) { roomGiftMsgList.insert(0, msg); diff --git a/lib/ui_kit/widgets/room/red_packet/room_red_packet_open_dialog.dart b/lib/ui_kit/widgets/room/red_packet/room_red_packet_open_dialog.dart index cf428dd..7782951 100644 --- a/lib/ui_kit/widgets/room/red_packet/room_red_packet_open_dialog.dart +++ b/lib/ui_kit/widgets/room/red_packet/room_red_packet_open_dialog.dart @@ -790,17 +790,13 @@ class _RoomRedPacketOpenCardState extends State<_RoomRedPacketOpenCard> { widget.data.senderName.trim().isNotEmpty ? widget.data.senderName.trim() : localizations.redEnvelope; - final message = localizations.roomRedPacketReceivedMessage( - _formatNumber(amount.round()), - senderName, - ); - final packetId = widget.data.packetId.trim(); - Provider.of(context, listen: false).sendRoomTextMessage( - message, - dedupKey: - packetId.isEmpty - ? null - : 'room-red-packet-claim-$packetId-${DateTime.now().microsecondsSinceEpoch}', + Provider.of( + context, + listen: false, + ).sendRoomRedPacketClaimMessage( + packetId: widget.data.packetId, + amount: amount, + packetSenderName: senderName, ); } diff --git a/lib/ui_kit/widgets/room/room_msg_item.dart b/lib/ui_kit/widgets/room/room_msg_item.dart index 0c48265..96cbccd 100644 --- a/lib/ui_kit/widgets/room/room_msg_item.dart +++ b/lib/ui_kit/widgets/room/room_msg_item.dart @@ -128,6 +128,9 @@ class _MsgItemState extends State { if (widget.msg.type == SCRoomMsgType.roomRedPacket) { return _buildRoomRedPacketMsg(context); } + if (widget.msg.type == SCRoomMsgType.roomRedPacketClaim) { + return _buildRoomRedPacketClaimMsg(context); + } if (widget.msg.user != null) { return Container( alignment: AlignmentDirectional.topStart, @@ -279,6 +282,65 @@ class _MsgItemState extends State { ); } + Widget _buildRoomRedPacketClaimMsg(BuildContext context) { + final localizations = SCAppLocalizations.of(context)!; + final packetSenderName = + (widget.msg.msg ?? '').trim().isNotEmpty + ? (widget.msg.msg ?? '').trim() + : localizations.redEnvelope; + final message = localizations.roomRedPacketReceivedMessage( + _formatAwardAmount(widget.msg.number), + packetSenderName, + ); + return Container( + alignment: AlignmentDirectional.topStart, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: width(5.w), + vertical: width(4), + ), + margin: EdgeInsets.symmetric( + horizontal: width(10), + ).copyWith(bottom: 6.w), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (widget.msg.user != null) ...[ + _buildUserInfoLine(context), + SizedBox(height: 6.w), + ], + Container( + constraints: BoxConstraints( + maxWidth: ScreenUtil().screenWidth * 0.7, + ), + decoration: BoxDecoration( + color: Colors.black38, + borderRadius: BorderRadius.only( + topRight: Radius.circular(15.w), + bottomLeft: Radius.circular(15.w), + bottomRight: Radius.circular(15.w), + ), + ), + padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 4.w), + margin: EdgeInsetsDirectional.only( + start: 54.w, + ).copyWith(bottom: 8.w), + child: Text( + message, + style: TextStyle( + fontSize: sp(13), + color: Color(_msgColor(widget.msg.type ?? "")), + fontWeight: FontWeight.w500, + ), + textAlign: TextAlign.start, + ), + ), + ], + ), + ), + ); + } + Widget _buildVipTextMessageBubble( PropsResources? resource, { required double maxBubbleWidth, diff --git a/需求进度.md b/需求进度.md index 49f2a1e..89b6ae9 100644 --- a/需求进度.md +++ b/需求进度.md @@ -559,6 +559,7 @@ - 已按最新反馈修正领取记录头像和跨房进房:领取记录空头像不再回退成红包图标,统一走项目默认头像;红包飘窗 `GO` 跨房点击直接进目标房间,不再弹进入房间二次确认。 - 已修正延时红包多入口数据不一致:公屏红包消息会同步写入待领缓存,右侧入口和领取弹层遇到同一 `packetId` 会合并接口列表、缓存和聊天 payload 的倒计时字段,避免飘屏 `GO`/右侧入口丢失倒计时;领取成功后右侧入口会优先按本地已领状态隐藏,避免接口刷新滞后导致残留。 - 已补齐红包发送后的 IM 广播:发送成功后除本机兜底展示外,会把 `{type: ROOM_RED_PACKET, data: payload}` 发送到当前房间 IM 群和当前语区 IM 群;同房用户通过房间群看到公屏/飘屏,房外或其它房同语区用户通过语区群看到飘屏,并继续依赖 `packetId` 去重避免重复展示。 +- 已修正红包领取成功公屏消息的多语言问题:领取后不再发送已翻译好的普通文本,改为 `ROOM_RED_PACKET_CLAIM` 结构化房间 IM,只传领取金额、红包发送人名和 `packetId`,公屏渲染时按当前客户端语言生成文案,避免英文用户看到阿语消息。 ## 已知问题 - 已接入语音房表情包素材第一版:桌面 `表情素材` 中的 `fluent_emoji` 与 `monkey` gif 已纳入项目资源,底部聊天入口改为图稿里的短白色胶囊并移除内部输入图标,右侧新增独立表情按钮;同一个房间输入弹层现在可从表情按钮直接打开表情包面板,原 unicode emoji 面板已替换为本地 gif 表情。发送逻辑同步按最新规则分流:用户在麦上发表情时只在自己麦位播放,不进入聊天列表;用户未上麦发表情时进入房间聊天框展示,不触发麦位动画。