import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:yumi/app_localizations.dart'; import 'package:yumi/ui_kit/components/sc_tts.dart'; import 'package:yumi/shared/data_sources/sources/local/user_manager.dart'; import 'package:yumi/shared/data_sources/sources/repositories/sc_room_repository_imp.dart'; import 'package:yumi/shared/data_sources/sources/repositories/sc_user_repository_impl.dart'; import 'package:yumi/shared/data_sources/sources/repositories/sc_vip_repository_imp.dart'; import 'package:yumi/shared/business_logic/models/req/sc_user_profile_cmd.dart'; import 'package:yumi/shared/business_logic/models/res/country_res.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'; import 'package:yumi/shared/business_logic/models/res/sc_user_identity_res.dart'; import 'package:yumi/shared/business_logic/models/res/sc_vip_res.dart'; import 'package:yumi/shared/tools/sc_cp_relation_level_utils.dart'; import 'package:yumi/shared/tools/sc_cp_relation_notice_utils.dart'; class SocialChatUserProfileManager extends ChangeNotifier { static const List _cpProfileRelationTypes = [ 'CP', 'BROTHER', 'SISTERS', ]; SCUserProfileCmd? editUser; void updateUserAvatar(String avatar) { editUser ??= SCUserProfileCmd(); editUser!.setUserAvatar = avatar; notifyListeners(); } void updateUserSex(num sex) { editUser ??= SCUserProfileCmd(); editUser!.setUserSex = sex; } void updateUserNickname(String nickname) { editUser ??= SCUserProfileCmd(); editUser!.setUserNickname = nickname; } void updateBornYear(num bornYear) { editUser ??= SCUserProfileCmd(); editUser!.setBornYear = bornYear; } void updateBornMonth(num bornMonth) { editUser ??= SCUserProfileCmd(); editUser!.setBornMonth = bornMonth; } void updateBornDay(num bornDay) { editUser ??= SCUserProfileCmd(); editUser!.setBornDay = bornDay; } void updateAge(num age) { editUser ??= SCUserProfileCmd(); editUser!.setAge = age; } void setCountry(Country country) { editUser ??= SCUserProfileCmd(); editUser!.setCountryCode = country.alphaTwo!; editUser!.setCountryId = country.id!; editUser!.setCountryName = country.countryName!; } void resetEditUserData() { editUser = null; notifyListeners(); } SocialChatUserProfile? get currentUserProfile => AccountStorage().getCurrentUser()?.userProfile; void syncCurrentUserProfile(SocialChatUserProfile? profile) { if (profile == null) { return; } final currentUser = AccountStorage().getCurrentUser(); if (currentUser != null) { currentUser.setUserProfile(profile); AccountStorage().setCurrentUser(currentUser); } if ((userProfile?.id ?? "").isNotEmpty && userProfile?.id == profile.id) { userProfile = profile; } notifyListeners(); } Future fetchUserProfileData({ bool loadGuardCount = true, bool refreshFamilyData = false, }) async { var us = AccountStorage().getCurrentUser(); String userId = us?.userProfile?.id ?? ""; if (userId.isEmpty) { return; } var userInfo = await SCAccountRepository().loadUserInfo(userId); userInfo = await _withCurrentVipLevel(userInfo, userId); userInfo = await _withCpCabinProfiles(userInfo, userId); syncCurrentUserProfile(userInfo); } SCUserIdentityRes? userIdentity; void getUserIdentity() async { if (kDebugMode) { final profile = AccountStorage().getCurrentUser()?.userProfile; debugPrint( '[SCUserIdentity] request start userId=${profile?.id}, account=${profile?.account}', ); } try { userIdentity = await SCAccountRepository().userIdentity(); if (kDebugMode) { debugPrint( '[SCUserIdentity] manager stored admin=${userIdentity?.admin}, ' 'manager=${userIdentity?.manager}, yumiManager=${userIdentity?.yumiManager}', ); } notifyListeners(); } catch (error) { if (kDebugMode) { debugPrint('[SCUserIdentity] request failed error=$error'); } } } /// 当前正在查看的个人详情资料,不用于承载登录用户自己的 Me 页数据。 SocialChatUserProfile? userProfile; void getUserInfoById(String userId) async { userProfile = null; final loadedProfile = await SCAccountRepository().loadUserInfo(userId); var mergedProfile = await _withCurrentVipLevel(loadedProfile, userId); mergedProfile = await _withCpCabinProfiles(mergedProfile, userId); userProfile = mergedProfile; notifyListeners(); } ///房间资料卡 RoomUserCardRes? userCardInfo; // List? userCountGuardResList; void roomUserCard(String roomId, String userId) async { userCardInfo = null; userCardInfo = await SCChatRoomRepository().roomUserCard(roomId, userId); userCardInfo = await _withCurrentVipLevelForCard(userCardInfo, userId); notifyListeners(); } Future _withCurrentVipLevelForCard( RoomUserCardRes? card, String userId, ) async { final profile = card?.userProfile; if (card == null || profile == null) { return card; } var mergedProfile = await _withCurrentVipLevel(profile, userId); mergedProfile = await _withCpCabinProfiles(mergedProfile, userId); if (mergedProfile == profile) { return card; } return card.copyWith(userProfile: mergedProfile); } Future _withCpCabinProfiles( SocialChatUserProfile profile, String userId, ) async { if (userId.trim().isEmpty) { return profile; } final cpPairs = []; final closeFriendPairs = []; await Future.wait( _cpProfileRelationTypes.map((relationType) async { final cabin = await _safeLoadCpCabin(userId, relationType); final cpPair = cabin?.cpPairUserProfileCO; if (cpPair == null || !_hasCpPair(cpPair)) { return; } final normalizedType = _normalizeCpRelationType( cpPair.relationType ?? relationType, ); final cabinLevelText = scCpRelationLevelTextFromCabin( cabin, fallbackText: cpPair.levelText, ); final rightsLevelText = await _safeLoadCurrentUserCpLevelText( userId: userId, cpPair: cpPair, relationType: normalizedType, fallbackText: cabinLevelText, ); final enrichedPair = cpPair.copyWith( relationType: normalizedType, cpValue: cpPair.cpValue ?? cabin?.cpVal?.toDouble(), levelText: rightsLevelText ?? cabinLevelText, dismissCost: cpPair.dismissCost ?? _cpDismissCostFromCabin(cabin), ); if (normalizedType == 'CP') { cpPairs.add(enrichedPair); } else { closeFriendPairs.add(enrichedPair); } }), ); if (kDebugMode) { debugPrint( '[CP][Profile] hydrate userId=$userId cp=${cpPairs.length} ' 'closeFriends=${closeFriendPairs.length}', ); } return profile.copyWith( cpList: cpPairs, closeFriendList: closeFriendPairs, isCpRelation: cpPairs.isNotEmpty, ); } Future _safeLoadCpCabin( String userId, String relationType, ) async { try { final cabin = await SCAccountRepository().cpCabin( userId, relationType: relationType, ); if (kDebugMode) { debugPrint( '[CP][Profile] cabin loaded userId=$userId relationType=$relationType ' 'hasPair=${_hasCpPair(cabin.cpPairUserProfileCO)} cpVal=${cabin.cpVal}', ); } return cabin; } catch (error) { if (kDebugMode) { debugPrint( '[CP][Profile] cabin failed userId=$userId ' 'relationType=$relationType error=$error', ); } return null; } } Future _safeLoadCurrentUserCpLevelText({ required String userId, required CPRes cpPair, required String relationType, String? fallbackText, }) async { if (!_isCurrentUserId(userId)) { return null; } final partnerUserId = _cpPartnerUserId(userId, cpPair); if (partnerUserId.isEmpty) { return null; } try { final config = await SCAccountRepository().cpRightsConfig( relationType: relationType, cpUserId: partnerUserId, ); return scCpRelationLevelTextFromRightsConfig( config, fallbackText: fallbackText, ); } catch (error) { if (kDebugMode) { debugPrint( '[CP][Profile] rightsConfig failed userId=$userId ' 'partnerUserId=$partnerUserId relationType=$relationType ' 'error=$error', ); } return null; } } String _cpPartnerUserId(String userId, CPRes cpPair) { final currentId = userId.trim(); final meUserId = cpPair.meUserId?.trim() ?? ""; final cpUserId = cpPair.cpUserId?.trim() ?? ""; if (currentId.isNotEmpty && currentId == cpUserId) { return meUserId; } return cpUserId; } bool _hasCpPair(CPRes? pair) { return (pair?.cpUserId?.trim().isNotEmpty ?? false) || (pair?.cpUserAvatar?.trim().isNotEmpty ?? false) || (pair?.cpUserNickname?.trim().isNotEmpty ?? false) || (pair?.meUserId?.trim().isNotEmpty ?? false) || (pair?.meUserAvatar?.trim().isNotEmpty ?? false) || (pair?.meUserNickname?.trim().isNotEmpty ?? false); } String _normalizeCpRelationType(String? relationType) { return scNormalizeCpRelationType(relationType); } int? _cpDismissCostFromCabin(SCCpCabinRes? cabin) { final directCost = cabin?.dismissCost; if (directCost != null) { return directCost; } final config = cabin?.currentCpCabinConfigCO; if (config is! Map) { return null; } return _cpIntValue( _firstCpConfigValue(config, const [ "dismissCost", "dismissGold", "dismissCoins", "dismissCoin", "cancelCost", "cancelGold", "removeCost", "partWaysCost", "consumeGold", "goldCost", "cost", "coins", "priceGold", ]), ); } dynamic _firstCpConfigValue(Map source, List keys) { for (final key in keys) { if (source.containsKey(key) && source[key] != null) { return source[key]; } } return null; } int? _cpIntValue(dynamic value) { if (value is int) { return value; } if (value is num) { return value.toInt(); } return int.tryParse(value?.toString() ?? ""); } Future _withCurrentVipLevel( SocialChatUserProfile profile, String userId, ) async { if (!_isCurrentUserId(userId)) { return profile; } final profileVipLevel = profile.vipLevel?.trim(); if (profileVipLevel != null && profileVipLevel.isNotEmpty && profile.getHeaddress() != null) { return profile; } final vipStatus = await _loadCurrentVipStatus(); final currentVipLevel = currentUserProfile?.vipLevel?.trim(); final resolvedVipLevel = profileVipLevel != null && profileVipLevel.isNotEmpty ? profileVipLevel : currentVipLevel != null && currentVipLevel.isNotEmpty ? currentVipLevel : _vipLevelFromStatus(vipStatus); var nextProfile = profile; if (resolvedVipLevel != null && resolvedVipLevel.isNotEmpty) { nextProfile = nextProfile.copyWith(vipLevel: resolvedVipLevel); } return socialChatProfileWithAvatarFrameResource( nextProfile, _avatarFramePropsFromVipStatus(vipStatus), expireTime: _expireTimeFromVipStatus(vipStatus), ); } bool _isCurrentUserId(String userId) { final currentUserId = AccountStorage().getCurrentUser()?.userProfile?.id; return currentUserId != null && currentUserId.isNotEmpty && currentUserId == userId; } Future _loadCurrentVipStatus() async { final repository = SCVipRepositoryImp(); try { final home = await repository.vipHome(); final state = home.state; if (state != null && state.levelInt > 0) { return state; } } catch (_) {} try { return repository.vipStatus(); } catch (_) { return null; } } PropsResources? _avatarFramePropsFromVipStatus(SCVipStatusRes? status) { if (status?.isActive != true) { return null; } final resource = status?.avatarFrame; return socialChatAvatarFrameProps( id: resource?.resourceId, name: resource?.name, sourceUrl: resource?.sourceResourceUrl, cover: resource?.coverUrl ?? resource?.cover, code: "VIP_AVATAR_FRAME", ); } String? _expireTimeFromVipStatus(SCVipStatusRes? status) { final expireAt = status?.expireAt?.trim(); if (expireAt == null || expireAt.isEmpty) { return null; } final normalized = expireAt.contains("T") ? expireAt : expireAt.replaceFirst(" ", "T"); return DateTime.tryParse(normalized)?.millisecondsSinceEpoch.toString(); } String? _vipLevelFromStatus(SCVipStatusRes? status) { if (status == null) { return null; } if (status.active == false) { return '0'; } final level = status.levelInt; return level > 0 ? level.toString() : '0'; } void followUser(String userId) async { var result = await SCAccountRepository().followUser(userId); if (result) { if (userCardInfo != null) { userCardInfo = userCardInfo?.copyWith(follow: !userCardInfo!.follow!); notifyListeners(); } } } double myBalance = 0.0; void balance() async { myBalance = await SCAccountRepository().balance(); notifyListeners(); } updateBalance(double m) { myBalance = m; notifyListeners(); } void inviteHostOpt(BuildContext ct, String id, String status) async { final successMessage = SCAppLocalizations.of(ct)!.operationSuccessful; try { await SCAccountRepository().inviteHost(id, status); getUserIdentity(); SCTts.show(successMessage); } catch (e) {} } void inviteAgentOpt(BuildContext ct, String id, String status) async { final successMessage = SCAppLocalizations.of(ct)!.operationSuccessful; try { await SCAccountRepository().inviteAgent(id, status); getUserIdentity(); SCTts.show(successMessage); } catch (e) {} } void inviteBDOpt(BuildContext ct, String id, String status) async { final successMessage = SCAppLocalizations.of(ct)!.operationSuccessful; try { await SCAccountRepository().inviteBD(id, status); getUserIdentity(); SCTts.show(successMessage); } catch (e) {} } void inviteBDLeader(BuildContext ct, String id, String status) async { final successMessage = SCAppLocalizations.of(ct)!.operationSuccessful; try { await SCAccountRepository().inviteBDLeader(id, status); getUserIdentity(); SCTts.show(successMessage); } catch (e) {} } void inviteRechargeAgent(BuildContext ct, String id, String status) async { final successMessage = SCAppLocalizations.of(ct)!.operationSuccessful; try { await SCAccountRepository().inviteRechargeAgent(id, status); getUserIdentity(); SCTts.show(successMessage); } catch (e) {} } Future cpRlationshipProcessApply( BuildContext ct, String id, bool status, ) async { final successMessage = SCAppLocalizations.of(ct)!.operationSuccessful; try { await SCAccountRepository().cpRelationshipProcessApply(id, status); await fetchUserProfileData(loadGuardCount: false); await refreshLoadedCpProfiles(); SCTts.show(successMessage); return true; } catch (e) { return false; } } Future refreshLoadedCpProfiles() async { final currentProfile = currentUserProfile; final currentUserId = currentProfile?.id; if (currentProfile != null && currentUserId != null && currentUserId.isNotEmpty) { syncCurrentUserProfile( await _withCpCabinProfiles(currentProfile, currentUserId), ); } final detailUserId = userProfile?.id; if (userProfile != null && detailUserId != 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) { userCardInfo = userCardInfo?.copyWith( userProfile: await _withCpCabinProfiles(cardProfile, cardUserId), ); } notifyListeners(); } }