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>(
currentContext,
listen: false,
).refreshLoadedCpProfiles(),
).refreshLoadedCpProfilesForUsers(userIds),
);
} catch (_) {}
try {

View File

@ -211,10 +211,24 @@ class SocialChatUserProfileManager extends ChangeNotifier {
Object? userCardLoadError;
bool isUserCardLoading = false;
int _userCardRequestSerial = 0;
int _userCardSessionSerial = 0;
int? _activeUserCardSessionSerial;
// 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 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<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({
required List<CPRes> cpPairs,
required List<CPRes> closeFriendPairs,
@ -878,31 +939,49 @@ class SocialChatUserProfileManager extends ChangeNotifier {
}
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 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),
);
}

View File

@ -67,6 +67,7 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
SocialChatUserProfileManager? userProvider;
String roomId = "";
SCUserIdentityRes? userIdentity;
int? _userCardSessionSerial;
@override
void initState() {
@ -96,13 +97,19 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
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

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