Merge branch 'feature' of gitea.haiyihy.com:hy/chatapp3-flutter into feature

This commit is contained in:
zhx 2026-05-25 13:12:51 +08:00
commit de4a06be77
4 changed files with 131 additions and 21 deletions

View File

@ -3401,7 +3401,7 @@ class RealTimeMessagingManager extends ChangeNotifier {
Provider.of<SocialChatUserProfileManager>( Provider.of<SocialChatUserProfileManager>(
currentContext, currentContext,
listen: false, listen: false,
).refreshLoadedCpProfiles(), ).refreshLoadedCpProfilesForUsers(userIds),
); );
} catch (_) {} } catch (_) {}
try { try {

View File

@ -211,10 +211,24 @@ class SocialChatUserProfileManager extends ChangeNotifier {
Object? userCardLoadError; Object? userCardLoadError;
bool isUserCardLoading = false; bool isUserCardLoading = false;
int _userCardRequestSerial = 0; int _userCardRequestSerial = 0;
int _userCardSessionSerial = 0;
int? _activeUserCardSessionSerial;
// List<UserCountGuardRes>? userCountGuardResList; // List<UserCountGuardRes>? userCountGuardResList;
Future<void> roomUserCard(String roomId, String userId) async { int beginRoomUserCardSession() {
final sessionSerial = ++_userCardSessionSerial;
_activeUserCardSessionSerial = sessionSerial;
return sessionSerial;
}
Future<void> roomUserCard(
String roomId,
String userId, {
int? sessionSerial,
}) async {
final activeSessionSerial = sessionSerial ?? beginRoomUserCardSession();
_activeUserCardSessionSerial = activeSessionSerial;
final requestSerial = ++_userCardRequestSerial; final requestSerial = ++_userCardRequestSerial;
final normalizedRoomId = roomId.trim(); final normalizedRoomId = roomId.trim();
final normalizedUserId = userId.trim(); final normalizedUserId = userId.trim();
@ -249,6 +263,7 @@ class SocialChatUserProfileManager extends ChangeNotifier {
card: card, card: card,
userId: normalizedUserId, userId: normalizedUserId,
requestSerial: requestSerial, requestSerial: requestSerial,
sessionSerial: activeSessionSerial,
), ),
); );
} catch (error, stackTrace) { } catch (error, stackTrace) {
@ -299,10 +314,13 @@ class SocialChatUserProfileManager extends ChangeNotifier {
required RoomUserCardRes? card, required RoomUserCardRes? card,
required String userId, required String userId,
required int requestSerial, required int requestSerial,
required int sessionSerial,
}) async { }) async {
try { try {
final hydratedCard = await _withCurrentVipLevelForCard(card, userId); final hydratedCard = await _withCurrentVipLevelForCard(card, userId);
if (requestSerial != _userCardRequestSerial || hydratedCard == null) { if (requestSerial != _userCardRequestSerial ||
sessionSerial != _activeUserCardSessionSerial ||
hydratedCard == null) {
return; return;
} }
userCardInfo = hydratedCard; userCardInfo = hydratedCard;
@ -318,8 +336,13 @@ class SocialChatUserProfileManager extends ChangeNotifier {
} }
} }
void clearRoomUserCard() { void clearRoomUserCard({int? sessionSerial}) {
if (sessionSerial != null &&
sessionSerial != _activeUserCardSessionSerial) {
return;
}
_userCardRequestSerial++; _userCardRequestSerial++;
_activeUserCardSessionSerial = null;
userCardInfo = null; userCardInfo = null;
userCardLoadError = null; userCardLoadError = null;
isUserCardLoading = false; isUserCardLoading = false;
@ -334,7 +357,7 @@ class SocialChatUserProfileManager extends ChangeNotifier {
return card; return card;
} }
var mergedProfile = await _withCurrentVipLevel(profile, userId); var mergedProfile = await _withCurrentVipLevel(profile, userId);
mergedProfile = await _withCpCabinProfiles(mergedProfile, userId); mergedProfile = await _withCpRelationshipProfiles(mergedProfile, userId);
if (mergedProfile == profile) { if (mergedProfile == profile) {
return card; return card;
} }
@ -464,6 +487,44 @@ class SocialChatUserProfileManager extends ChangeNotifier {
); );
} }
Future<SocialChatUserProfile> _withCpRelationshipProfiles(
SocialChatUserProfile profile,
String userId,
) async {
if (userId.trim().isEmpty) {
return profile;
}
final cpPairs = <CPRes>[];
final closeFriendPairs = <CPRes>[];
_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({ void _addCpRelationPairs({
required List<CPRes> cpPairs, required List<CPRes> cpPairs,
required List<CPRes> closeFriendPairs, required List<CPRes> closeFriendPairs,
@ -878,31 +939,49 @@ class SocialChatUserProfileManager extends ChangeNotifier {
} }
Future<void> refreshLoadedCpProfiles() async { Future<void> refreshLoadedCpProfiles() async {
await _refreshLoadedCpProfilesForUserIds(null);
}
Future<void> refreshLoadedCpProfilesForUsers(Set<String> userIds) async {
final normalizedUserIds =
userIds.map((userId) => userId.trim()).where((userId) {
return userId.isNotEmpty;
}).toSet();
if (normalizedUserIds.isEmpty) {
return;
}
await _refreshLoadedCpProfilesForUserIds(normalizedUserIds);
}
Future<void> _refreshLoadedCpProfilesForUserIds(Set<String>? 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 currentProfile = currentUserProfile;
final currentUserId = currentProfile?.id; final currentUserId = refreshedUserId(currentProfile?.id);
if (currentProfile != null && if (currentProfile != null && currentUserId.isNotEmpty) {
currentUserId != null &&
currentUserId.isNotEmpty) {
syncCurrentUserProfile( syncCurrentUserProfile(
await _withCpCabinProfiles(currentProfile, currentUserId), await _withCpCabinProfiles(currentProfile, currentUserId),
); );
} }
final detailUserId = userProfile?.id; final detailUserId = refreshedUserId(userProfile?.id);
if (userProfile != null && if (userProfile != null && detailUserId.isNotEmpty) {
detailUserId != null &&
detailUserId.isNotEmpty) {
userProfile = await _withCpCabinProfiles(userProfile!, detailUserId); userProfile = await _withCpCabinProfiles(userProfile!, detailUserId);
} }
final cardProfile = userCardInfo?.userProfile; final cardProfile = userCardInfo?.userProfile;
final cardUserId = cardProfile?.id; final cardUserId = refreshedUserId(cardProfile?.id);
if (userCardInfo != null && if (userCardInfo != null && cardProfile != null && cardUserId.isNotEmpty) {
cardProfile != null &&
cardUserId != null &&
cardUserId.isNotEmpty) {
userCardInfo = userCardInfo?.copyWith( userCardInfo = userCardInfo?.copyWith(
userProfile: await _withCpCabinProfiles(cardProfile, cardUserId), userProfile: await _withCpRelationshipProfiles(cardProfile, cardUserId),
); );
} }

View File

@ -67,6 +67,7 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
SocialChatUserProfileManager? userProvider; SocialChatUserProfileManager? userProvider;
String roomId = ""; String roomId = "";
SCUserIdentityRes? userIdentity; SCUserIdentityRes? userIdentity;
int? _userCardSessionSerial;
@override @override
void initState() { void initState() {
@ -96,13 +97,19 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
listen: false, listen: false,
).currenRoom?.roomProfile?.roomProfile?.id ?? ).currenRoom?.roomProfile?.roomProfile?.id ??
""; "";
userProvider?.roomUserCard(roomId, widget.userId ?? ""); final sessionSerial = userProvider?.beginRoomUserCardSession();
_userCardSessionSerial = sessionSerial;
userProvider?.roomUserCard(
roomId,
widget.userId ?? "",
sessionSerial: sessionSerial,
);
} }
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
userProvider?.clearRoomUserCard(); userProvider?.clearRoomUserCard(sessionSerial: _userCardSessionSerial);
} }
@override @override

View File

@ -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);
});
}