bug 修复

This commit is contained in:
roxy 2026-05-09 16:55:08 +08:00
parent 4aae854b78
commit c810e645dc
7 changed files with 110 additions and 9 deletions

View File

@ -115,6 +115,12 @@ class _SCIndexPageState extends State<SCIndexPage>
if (state != AppLifecycleState.resumed) {
return;
}
unawaited(
Provider.of<RtmProvider>(
context,
listen: false,
).syncRoomRedPacketBroadcastGroup(),
);
WidgetsBinding.instance.addPostFrameCallback((_) {
unawaited(_showEntryPopupIfNeeded());
});
@ -163,6 +169,14 @@ class _SCIndexPageState extends State<SCIndexPage>
return;
}
OverlayManager().setHomeRootTabsVisible(visible);
if (visible) {
unawaited(
Provider.of<RtmProvider>(
context,
listen: false,
).syncRoomRedPacketBroadcastGroup(),
);
}
}
@override

View File

@ -3033,6 +3033,12 @@ class RealTimeCommunicationManager extends ChangeNotifier {
}
final normalizedPacketId = packetId.trim();
final normalizedSenderName = packetSenderName.trim();
final currentUser = AccountStorage().getCurrentUser()?.userProfile;
final currentUserId = (currentUser?.id ?? "").trim();
final dedupKey =
normalizedPacketId.isNotEmpty && currentUserId.isNotEmpty
? 'room-red-packet-claim-$normalizedPacketId-$currentUserId'
: null;
unawaited(
rtmProvider?.dispatchMessage(
Msg(
@ -3041,11 +3047,8 @@ class RealTimeCommunicationManager extends ChangeNotifier {
type: SCRoomMsgType.roomRedPacketClaim,
role: currenRoom?.entrants?.roles ?? "",
number: amount,
giftBatchId:
normalizedPacketId.isEmpty
? null
: 'room-red-packet-claim-$normalizedPacketId',
user: AccountStorage().getCurrentUser()?.userProfile,
giftBatchId: dedupKey,
user: currentUser,
),
) ??
Future<void>.value(),

View File

@ -1164,6 +1164,13 @@ class RealTimeMessagingManager extends ChangeNotifier {
);
return;
}
if (msg.type == SCRoomMsgType.roomRedPacketClaim &&
_hasRoomRedPacketClaimMessage(msg)) {
debugPrint(
'[RoomRedPacket][Claim] skip duplicate key=${_roomRedPacketClaimMessageKey(msg)}',
);
return;
}
roomAllMsgList.insert(0, msg);
if (roomAllMsgList.length > 250) {
@ -1280,6 +1287,35 @@ class RealTimeMessagingManager extends ChangeNotifier {
return null;
}
bool _hasRoomRedPacketClaimMessage(Msg msg) {
final key = _roomRedPacketClaimMessageKey(msg);
if (key == null || key.isEmpty) {
return false;
}
return roomAllMsgList.any(
(item) =>
item.type == SCRoomMsgType.roomRedPacketClaim &&
_roomRedPacketClaimMessageKey(item) == key,
);
}
String? _roomRedPacketClaimMessageKey(Msg msg) {
if (msg.type != SCRoomMsgType.roomRedPacketClaim) {
return null;
}
final stableKey = (msg.giftBatchId ?? '').trim();
if (stableKey.isNotEmpty) {
return stableKey;
}
final userId = (msg.user?.id ?? '').trim();
final amount = msg.number?.toString() ?? '';
final time = msg.time?.toString() ?? '';
if (userId.isEmpty || amount.isEmpty || time.isEmpty) {
return null;
}
return ['legacy', userId, msg.msg ?? '', amount, time].join('|');
}
Msg? _mergeGiftMessageIfNeeded(Msg incoming) {
if (incoming.type != SCRoomMsgType.gift &&
incoming.type != SCRoomMsgType.luckGiftAnimOther) {

View File

@ -563,6 +563,9 @@ class OverlayManager {
if (message.type == 4 && rtcProvider.shouldShowRoomVisualEffects) {
return true;
}
if (message.type == 4) {
return _homeRootTabsVisible;
}
if (SCGlobalConfig.isFloatingBroadcastRoomOnly) {
return false;
}

View File

@ -312,10 +312,17 @@ class SCAccountRepository implements SocialChatUserRepository {
///user/user-profile
@override
Future<SocialChatUserProfile> loadUserInfo(String userId) async {
Future<SocialChatUserProfile> loadUserInfo(
String userId, {
bool silentErrorToast = false,
}) async {
final result = await http.get(
"2fa1d4f56bb726558904ce2a50b83f961e1cf9b945681bdfb3d4cf7a5ecfc943",
queryParams: {"userId": userId},
extra:
silentErrorToast
? const {BaseNetworkClient.silentErrorToastKey: true}
: null,
fromJson: (json) => SocialChatUserProfile.fromJson(json),
);
return result;

View File

@ -51,6 +51,11 @@ class MsgItem extends StatefulWidget {
}
class _MsgItemState extends State<MsgItem> {
static const Duration _userInfoFailureRetryInterval = Duration(minutes: 5);
static final Map<String, Future<SocialChatUserProfile?>> _userInfoFutures =
{};
static final Map<String, DateTime> _userInfoFailedAt = {};
@override
Widget build(BuildContext context) {
//gift
@ -1651,14 +1656,19 @@ class _MsgItemState extends State<MsgItem> {
final userId = widget.msg.user?.id;
if ((widget.msg.needUpDataUserInfo) ?? false) {
SCRoomUtils.roomUsersMap.remove(userId ?? "");
if ((userId ?? "").isNotEmpty) {
_userInfoFutures.remove(userId);
_userInfoFailedAt.remove(userId);
}
widget.msg.needUpDataUserInfo = false;
}
if (userId == null || userId.isEmpty) {
return _buildPendingUserInfoLine(context);
}
return SCRoomUtils.roomUsersMap[userId] == null
? FutureBuilder(
future: SCAccountRepository().loadUserInfo(userId),
builder: (ct, AsyncSnapshot<SocialChatUserProfile> snapshot) {
? FutureBuilder<SocialChatUserProfile?>(
future: _loadRoomUserInfoSilently(userId),
builder: (ct, AsyncSnapshot<SocialChatUserProfile?> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
SocialChatUserProfile user = snapshot.data!;
@ -1672,6 +1682,32 @@ class _MsgItemState extends State<MsgItem> {
: _buildNewUserInfoLine(context, SCRoomUtils.roomUsersMap[userId]!);
}
Future<SocialChatUserProfile?> _loadRoomUserInfoSilently(String userId) {
final failedAt = _userInfoFailedAt[userId];
if (failedAt != null &&
DateTime.now().difference(failedAt) < _userInfoFailureRetryInterval) {
return Future.value(null);
}
return _userInfoFutures.putIfAbsent(userId, () async {
try {
final user = await SCAccountRepository().loadUserInfo(
userId,
silentErrorToast: true,
);
SCRoomUtils.roomUsersMap[user.id ?? userId] = user;
_userInfoFailedAt.remove(userId);
return user;
} catch (error) {
_userInfoFailedAt[userId] = DateTime.now();
_userInfoFutures.remove(userId);
debugPrint(
'[RoomChat][UserInfo] load failed userId=$userId error=$error',
);
return null;
}
});
}
Widget _buildPendingUserInfoLine(BuildContext context) {
return Row(
children: [

View File

@ -560,6 +560,8 @@
- 已修正延时红包多入口数据不一致:公屏红包消息会同步写入待领缓存,右侧入口和领取弹层遇到同一 `packetId` 会合并接口列表、缓存和聊天 payload 的倒计时字段,避免飘屏 `GO`/右侧入口丢失倒计时;领取成功后右侧入口会优先按本地已领状态隐藏,避免接口刷新滞后导致残留。
- 已补齐红包发送后的 IM 广播:发送成功后除本机兜底展示外,会把 `{type: ROOM_RED_PACKET, data: payload}` 发送到当前房间 IM 群和当前语区 IM 群;同房用户通过房间群看到公屏/飘屏,房外或其它房同语区用户通过语区群看到飘屏,并继续依赖 `packetId` 去重避免重复展示。
- 已修正红包领取成功公屏消息的多语言问题:领取后不再发送已翻译好的普通文本,改为 `ROOM_RED_PACKET_CLAIM` 结构化房间 IM只传领取金额、红包发送人名和 `packetId`,公屏渲染时按当前客户端语言生成文案,避免英文用户看到阿语消息。
- 已补强房外延时红包飘屏和领取通知去重:首页四个一级 Tab 可见/回到前台时会重新同步当前语区红包 IM 群;语区红包飘屏在首页 Tab 中不再受“只看房间飘屏”设置影响;领取成功公屏通知按 `packetId + 领取人ID` 生成稳定去重键,避免本地插入和 IM 回包/历史拉取造成两条一模一样的领取消息。
- 已定位并修复公屏上滑历史反复弹 `user info not found`:历史消息 item 重建时会重复调用用户资料接口,缺失用户返回错误后被网络层 toast现在房间公屏补拉用户资料改为静默请求并对同一 userId 的请求/失败结果做缓存5 分钟内不再反复请求同一个不存在用户。
## 已知问题
- 已接入语音房表情包素材第一版:桌面 `表情素材` 中的 `fluent_emoji``monkey` gif 已纳入项目资源,底部聊天入口改为图稿里的短白色胶囊并移除内部输入图标,右侧新增独立表情按钮;同一个房间输入弹层现在可从表情按钮直接打开表情包面板,原 unicode emoji 面板已替换为本地 gif 表情。发送逻辑同步按最新规则分流:用户在麦上发表情时只在自己麦位播放,不进入聊天列表;用户未上麦发表情时进入房间聊天框展示,不触发麦位动画。