bug 修复
This commit is contained in:
parent
4aae854b78
commit
c810e645dc
@ -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
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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: [
|
||||
|
||||
2
需求进度.md
2
需求进度.md
@ -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 表情。发送逻辑同步按最新规则分流:用户在麦上发表情时只在自己麦位播放,不进入聊天列表;用户未上麦发表情时进入房间聊天框展示,不触发麦位动画。
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user