diff --git a/lib/services/audio/rtm_manager.dart b/lib/services/audio/rtm_manager.dart index 0722fbb..bc74275 100644 --- a/lib/services/audio/rtm_manager.dart +++ b/lib/services/audio/rtm_manager.dart @@ -3401,7 +3401,7 @@ class RealTimeMessagingManager extends ChangeNotifier { Provider.of( currentContext, listen: false, - ).refreshLoadedCpProfiles(), + ).refreshLoadedCpProfilesForUsers(userIds), ); } catch (_) {} try { diff --git a/lib/services/auth/user_profile_manager.dart b/lib/services/auth/user_profile_manager.dart index 8f1f2bf..33aaf5d 100644 --- a/lib/services/auth/user_profile_manager.dart +++ b/lib/services/auth/user_profile_manager.dart @@ -211,10 +211,24 @@ class SocialChatUserProfileManager extends ChangeNotifier { Object? userCardLoadError; bool isUserCardLoading = false; int _userCardRequestSerial = 0; + int _userCardSessionSerial = 0; + int? _activeUserCardSessionSerial; // List? userCountGuardResList; - Future roomUserCard(String roomId, String userId) async { + int beginRoomUserCardSession() { + final sessionSerial = ++_userCardSessionSerial; + _activeUserCardSessionSerial = sessionSerial; + return sessionSerial; + } + + Future roomUserCard( + String roomId, + String userId, { + int? sessionSerial, + }) async { + final activeSessionSerial = sessionSerial ?? beginRoomUserCardSession(); + _activeUserCardSessionSerial = activeSessionSerial; final requestSerial = ++_userCardRequestSerial; final normalizedRoomId = roomId.trim(); final normalizedUserId = userId.trim(); @@ -249,6 +263,7 @@ class SocialChatUserProfileManager extends ChangeNotifier { card: card, userId: normalizedUserId, requestSerial: requestSerial, + sessionSerial: activeSessionSerial, ), ); } catch (error, stackTrace) { @@ -299,10 +314,13 @@ class SocialChatUserProfileManager extends ChangeNotifier { required RoomUserCardRes? card, required String userId, required int requestSerial, + required int sessionSerial, }) async { try { final hydratedCard = await _withCurrentVipLevelForCard(card, userId); - if (requestSerial != _userCardRequestSerial || hydratedCard == null) { + if (requestSerial != _userCardRequestSerial || + sessionSerial != _activeUserCardSessionSerial || + hydratedCard == null) { return; } userCardInfo = hydratedCard; @@ -318,8 +336,13 @@ class SocialChatUserProfileManager extends ChangeNotifier { } } - void clearRoomUserCard() { + void clearRoomUserCard({int? sessionSerial}) { + if (sessionSerial != null && + sessionSerial != _activeUserCardSessionSerial) { + return; + } _userCardRequestSerial++; + _activeUserCardSessionSerial = null; userCardInfo = null; userCardLoadError = null; isUserCardLoading = false; @@ -334,7 +357,7 @@ class SocialChatUserProfileManager extends ChangeNotifier { return card; } var mergedProfile = await _withCurrentVipLevel(profile, userId); - mergedProfile = await _withCpCabinProfiles(mergedProfile, userId); + mergedProfile = await _withCpRelationshipProfiles(mergedProfile, userId); if (mergedProfile == profile) { return card; } @@ -464,6 +487,44 @@ class SocialChatUserProfileManager extends ChangeNotifier { ); } + Future _withCpRelationshipProfiles( + SocialChatUserProfile profile, + String userId, + ) async { + if (userId.trim().isEmpty) { + return profile; + } + final cpPairs = []; + final closeFriendPairs = []; + _addCpRelationPairs( + cpPairs: cpPairs, + closeFriendPairs: closeFriendPairs, + relations: profile.cpList, + fallbackRelationType: 'CP', + ); + _addCpRelationPairs( + cpPairs: cpPairs, + closeFriendPairs: closeFriendPairs, + relations: profile.closeFriendList, + ); + await Future.wait( + _cpProfileRelationTypes.map((relationType) async { + final pairs = await _safeLoadCpRelationshipPairs(userId, relationType); + _addCpRelationPairs( + cpPairs: cpPairs, + closeFriendPairs: closeFriendPairs, + relations: pairs, + fallbackRelationType: relationType, + ); + }), + ); + return profile.copyWith( + cpList: cpPairs, + closeFriendList: closeFriendPairs, + isCpRelation: cpPairs.isNotEmpty, + ); + } + void _addCpRelationPairs({ required List cpPairs, required List closeFriendPairs, @@ -878,31 +939,49 @@ class SocialChatUserProfileManager extends ChangeNotifier { } Future refreshLoadedCpProfiles() async { + await _refreshLoadedCpProfilesForUserIds(null); + } + + Future refreshLoadedCpProfilesForUsers(Set userIds) async { + final normalizedUserIds = + userIds.map((userId) => userId.trim()).where((userId) { + return userId.isNotEmpty; + }).toSet(); + if (normalizedUserIds.isEmpty) { + return; + } + await _refreshLoadedCpProfilesForUserIds(normalizedUserIds); + } + + Future _refreshLoadedCpProfilesForUserIds(Set? userIds) async { + String refreshedUserId(String? userId) { + final normalizedUserId = userId?.trim() ?? ""; + if (normalizedUserId.isEmpty) { + return ""; + } + return userIds == null || userIds.contains(normalizedUserId) + ? normalizedUserId + : ""; + } + final currentProfile = currentUserProfile; - final currentUserId = currentProfile?.id; - if (currentProfile != null && - currentUserId != null && - currentUserId.isNotEmpty) { + final currentUserId = refreshedUserId(currentProfile?.id); + if (currentProfile != null && currentUserId.isNotEmpty) { syncCurrentUserProfile( await _withCpCabinProfiles(currentProfile, currentUserId), ); } - final detailUserId = userProfile?.id; - if (userProfile != null && - detailUserId != null && - detailUserId.isNotEmpty) { + final detailUserId = refreshedUserId(userProfile?.id); + if (userProfile != null && detailUserId.isNotEmpty) { userProfile = await _withCpCabinProfiles(userProfile!, detailUserId); } final cardProfile = userCardInfo?.userProfile; - final cardUserId = cardProfile?.id; - if (userCardInfo != null && - cardProfile != null && - cardUserId != null && - cardUserId.isNotEmpty) { + final cardUserId = refreshedUserId(cardProfile?.id); + if (userCardInfo != null && cardProfile != null && cardUserId.isNotEmpty) { userCardInfo = userCardInfo?.copyWith( - userProfile: await _withCpCabinProfiles(cardProfile, cardUserId), + userProfile: await _withCpRelationshipProfiles(cardProfile, cardUserId), ); } diff --git a/lib/ui_kit/widgets/room/room_user_info_card.dart b/lib/ui_kit/widgets/room/room_user_info_card.dart index e9fdbb1..ae335a4 100644 --- a/lib/ui_kit/widgets/room/room_user_info_card.dart +++ b/lib/ui_kit/widgets/room/room_user_info_card.dart @@ -67,6 +67,7 @@ class _RoomUserInfoCardState extends State { SocialChatUserProfileManager? userProvider; String roomId = ""; SCUserIdentityRes? userIdentity; + int? _userCardSessionSerial; @override void initState() { @@ -96,13 +97,19 @@ class _RoomUserInfoCardState extends State { listen: false, ).currenRoom?.roomProfile?.roomProfile?.id ?? ""; - userProvider?.roomUserCard(roomId, widget.userId ?? ""); + final sessionSerial = userProvider?.beginRoomUserCardSession(); + _userCardSessionSerial = sessionSerial; + userProvider?.roomUserCard( + roomId, + widget.userId ?? "", + sessionSerial: sessionSerial, + ); } @override void dispose() { super.dispose(); - userProvider?.clearRoomUserCard(); + userProvider?.clearRoomUserCard(sessionSerial: _userCardSessionSerial); } @override diff --git a/test/user_profile_manager_room_card_session_test.dart b/test/user_profile_manager_room_card_session_test.dart new file mode 100644 index 0000000..068c9c6 --- /dev/null +++ b/test/user_profile_manager_room_card_session_test.dart @@ -0,0 +1,24 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:yumi/services/auth/user_profile_manager.dart'; +import 'package:yumi/shared/business_logic/models/res/login_res.dart'; +import 'package:yumi/shared/business_logic/models/res/room_user_card_res.dart'; + +void main() { + test('stale room card dispose does not clear the active card session', () { + final manager = SocialChatUserProfileManager(); + final staleSession = manager.beginRoomUserCardSession(); + final activeSession = manager.beginRoomUserCardSession(); + + manager.userCardInfo = RoomUserCardRes( + userProfile: SocialChatUserProfile(id: 'active-user'), + ); + + manager.clearRoomUserCard(sessionSerial: staleSession); + + expect(manager.userCardInfo?.userProfile?.id, 'active-user'); + + manager.clearRoomUserCard(sessionSerial: activeSession); + + expect(manager.userCardInfo, isNull); + }); +}