修复问题
This commit is contained in:
parent
de4a06be77
commit
5f6bd6f5f8
@ -889,6 +889,9 @@ class _MessageItem extends StatelessWidget {
|
||||
return null;
|
||||
}
|
||||
final state = _cpInviteStateForMessage(data);
|
||||
if (_shouldRenderCpInviteCardForData(data, state)) {
|
||||
return null;
|
||||
}
|
||||
if (state == _CpInviteMessageState.pending || !_isCpInvitePayload(data)) {
|
||||
return null;
|
||||
}
|
||||
@ -1325,6 +1328,21 @@ class _MessageItem extends StatelessWidget {
|
||||
return _firstNonBlankString([nickname, actualAccount, account, fallback]);
|
||||
}
|
||||
|
||||
bool _shouldRenderCpInviteCardForData(
|
||||
Map<String, dynamic> data, [
|
||||
_CpInviteMessageState? state,
|
||||
]) {
|
||||
if (!_isCpInvitePayload(data)) {
|
||||
return false;
|
||||
}
|
||||
final applyId = _cpApplyIdFromData(data);
|
||||
if (applyId.isEmpty || _cpInviteFromMessageData(data) == null) {
|
||||
return false;
|
||||
}
|
||||
final effectiveState = state ?? _cpInviteStateForMessage(data);
|
||||
return effectiveState != _CpInviteMessageState.accepted;
|
||||
}
|
||||
|
||||
String _firstNonBlankString(
|
||||
Iterable<String?> values, {
|
||||
String fallback = "User",
|
||||
@ -1506,7 +1524,7 @@ class _MessageItem extends StatelessWidget {
|
||||
},
|
||||
context,
|
||||
);
|
||||
} else if (type == SCSysytemMessageType.CP_BUILD.name) {
|
||||
} else if (_shouldRenderCpInviteCardForData(data)) {
|
||||
final cpInvite = _cpInviteFromMessageData(data);
|
||||
return _buildCpBuildMessage(data, (ct, content) {
|
||||
_showMsgItemMenu(ct, content);
|
||||
|
||||
@ -19,6 +19,7 @@ import 'package:yumi/shared/tools/sc_gift_vap_svga_manager.dart';
|
||||
import 'package:yumi/shared/data_sources/sources/local/user_manager.dart';
|
||||
import 'package:yumi/shared/data_sources/sources/remote/net/api.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/business_logic/models/res/login_res.dart';
|
||||
import 'package:yumi/shared/tools/sc_cp_gift_relation_utils.dart';
|
||||
import 'package:yumi/main.dart';
|
||||
@ -1519,6 +1520,8 @@ class _GiftPageState extends State<GiftPage> with TickerProviderStateMixin {
|
||||
'giftType=$giftType',
|
||||
);
|
||||
|
||||
await _showCpGiftRelationCheckToastIfNeeded(request);
|
||||
|
||||
try {
|
||||
final repository = SCChatRoomRepository();
|
||||
_giftFxLog(
|
||||
@ -1725,6 +1728,49 @@ class _GiftPageState extends State<GiftPage> with TickerProviderStateMixin {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _showCpGiftRelationCheckToastIfNeeded(
|
||||
_GiftSendRequest request,
|
||||
) async {
|
||||
final relationType = request.cpRelationType;
|
||||
if (relationType == null || relationType.trim().isEmpty) {
|
||||
return;
|
||||
}
|
||||
final acceptUserId = request.acceptUserIds
|
||||
.map((userId) => userId.trim())
|
||||
.firstWhere((userId) => userId.isNotEmpty, orElse: () => '');
|
||||
if (acceptUserId.isEmpty) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final result = await SCAccountRepository().cpGiftRelationCheck(
|
||||
acceptUserId: acceptUserId,
|
||||
relationType: relationType,
|
||||
);
|
||||
final message = result.msg.trim();
|
||||
_giftFxLog(
|
||||
'cp gift relation check '
|
||||
'acceptUserId=$acceptUserId '
|
||||
'relationType=$relationType '
|
||||
'status=${result.status} '
|
||||
'msg=$message '
|
||||
'userCount=${result.userRelationCount}/${result.maxRelationCount} '
|
||||
'acceptCount=${result.acceptUserRelationCount}/${result.maxRelationCount}',
|
||||
);
|
||||
if (!result.status &&
|
||||
message.isNotEmpty &&
|
||||
message.toUpperCase() != 'OK') {
|
||||
SCTts.show(message);
|
||||
}
|
||||
} catch (error) {
|
||||
_giftFxLog(
|
||||
'cp gift relation check skipped '
|
||||
'acceptUserId=$acceptUserId '
|
||||
'relationType=$relationType '
|
||||
'error=$error',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<MicRes>> _giveBackpackGiftToRecipients(
|
||||
SCChatRoomRepository repository,
|
||||
_GiftSendRequest request,
|
||||
@ -1857,7 +1903,7 @@ class _GiftPageState extends State<GiftPage> with TickerProviderStateMixin {
|
||||
);
|
||||
}
|
||||
num coins = (gift.giftCandy ?? 0) * quantity;
|
||||
if (coins > 9999) {
|
||||
if (coins > 9999 && !_isCpGift(gift)) {
|
||||
var fMsg = SCFloatingMessage(
|
||||
type: 1,
|
||||
userId: AccountStorage().getCurrentUser()?.userProfile?.id ?? "",
|
||||
@ -1900,7 +1946,8 @@ class _GiftPageState extends State<GiftPage> with TickerProviderStateMixin {
|
||||
'animationCount=$animationCount',
|
||||
);
|
||||
SCGiftVapSvgaManager().play(gift.giftSourceUrl!);
|
||||
} else if (SCGlobalConfig.isLowPerformanceDevice &&
|
||||
} else if (!_isCpGift(gift) &&
|
||||
SCGlobalConfig.isLowPerformanceDevice &&
|
||||
SCGlobalConfig.isGiftSpecialEffects &&
|
||||
(rtcProvider?.shouldShowRoomVisualEffects ?? false)) {
|
||||
_enqueueLowPerformanceGiftCompensation(
|
||||
|
||||
@ -21,10 +21,12 @@ import 'package:yumi/services/music/room_music_manager.dart';
|
||||
import 'package:yumi/services/audio/rtm_manager.dart';
|
||||
import 'package:yumi/shared/tools/sc_gift_vap_svga_manager.dart';
|
||||
import 'package:yumi/shared/tools/sc_lucky_gift_win_sound_player.dart';
|
||||
import 'package:yumi/shared/tools/sc_cp_gift_relation_utils.dart';
|
||||
import 'package:yumi/shared/tools/sc_network_image_utils.dart';
|
||||
import 'package:yumi/shared/tools/sc_path_utils.dart';
|
||||
import 'package:yumi/shared/tools/sc_room_effect_scheduler.dart';
|
||||
import 'package:yumi/shared/tools/sc_room_top_layer_guard.dart';
|
||||
import 'package:yumi/shared/data_sources/models/message/sc_floating_message.dart';
|
||||
import 'package:yumi/shared/data_sources/sources/local/floating_screen_manager.dart';
|
||||
import 'package:yumi/ui_kit/widgets/room/anim/l_gift_animal_view.dart';
|
||||
import 'package:yumi/ui_kit/widgets/room/anim/room_gift_seat_flight_overlay.dart';
|
||||
@ -741,6 +743,7 @@ class _VoiceRoomPageState extends State<VoiceRoomPage>
|
||||
}
|
||||
|
||||
final giftPhoto = (msg.gift?.giftPhoto ?? "").trim();
|
||||
_enqueueCpGiftFloatingIfNeeded(msg);
|
||||
if (_supportsComboMilestoneEffects(msg)) {
|
||||
_handleComboMilestoneVisuals(msg, targetGroupKey);
|
||||
}
|
||||
@ -762,6 +765,48 @@ class _VoiceRoomPageState extends State<VoiceRoomPage>
|
||||
);
|
||||
}
|
||||
|
||||
void _enqueueCpGiftFloatingIfNeeded(Msg msg) {
|
||||
final gift = msg.gift;
|
||||
if (!scIsCpGift(gift) || gift == null) {
|
||||
return;
|
||||
}
|
||||
final quantity = msg.number ?? 0;
|
||||
if (quantity <= 0) {
|
||||
return;
|
||||
}
|
||||
final roomId = _resolveGiftFloatingRoomId(msg);
|
||||
OverlayManager().addMessage(
|
||||
SCFloatingMessage(
|
||||
type: 1,
|
||||
priority: 900,
|
||||
userId: msg.user?.id ?? "",
|
||||
toUserId: msg.toUser?.id ?? "",
|
||||
userAvatarUrl: msg.user?.userAvatar ?? "",
|
||||
toUserAvatarUrl: msg.toUser?.userAvatar ?? "",
|
||||
userName: msg.user?.userNickname ?? "",
|
||||
toUserName: msg.toUser?.userNickname ?? "",
|
||||
giftUrl: gift.giftPhoto ?? "",
|
||||
giftId: gift.id,
|
||||
giftTab: scCpRelationTypeForGift(gift),
|
||||
number: quantity,
|
||||
coins: quantity * (gift.giftCandy ?? 0),
|
||||
roomId: roomId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _resolveGiftFloatingRoomId(Msg msg) {
|
||||
final messageRoomId = (msg.msg ?? "").trim();
|
||||
if (messageRoomId.isNotEmpty) {
|
||||
return messageRoomId;
|
||||
}
|
||||
return Provider.of<RtcProvider>(
|
||||
context,
|
||||
listen: false,
|
||||
).currenRoom?.roomProfile?.roomProfile?.id ??
|
||||
"";
|
||||
}
|
||||
|
||||
void _luckyGiftRewardTickerListener(Msg msg) {
|
||||
if (!Provider.of<RtcProvider>(
|
||||
context,
|
||||
|
||||
@ -259,9 +259,7 @@ class _EditUserInfoPage2State extends State<EditUserInfoPage2>
|
||||
sex == 1
|
||||
? SCAppLocalizations.of(context)!.man
|
||||
: SCAppLocalizations.of(context)!.woman,
|
||||
() {
|
||||
_showSexDialog();
|
||||
},
|
||||
null,
|
||||
),
|
||||
|
||||
_buildItem(
|
||||
@ -538,6 +536,7 @@ class _EditUserInfoPage2State extends State<EditUserInfoPage2>
|
||||
}
|
||||
}
|
||||
|
||||
// ignore: unused_element
|
||||
void _showSexDialog() {
|
||||
showCenterDialog(
|
||||
context,
|
||||
@ -619,7 +618,7 @@ class _EditUserInfoPage2State extends State<EditUserInfoPage2>
|
||||
);
|
||||
}
|
||||
|
||||
_buildItem(String title, String value, Function() func) {
|
||||
_buildItem(String title, String value, Function()? func) {
|
||||
return SCDebounceWidget(
|
||||
child: Column(
|
||||
children: [
|
||||
@ -638,11 +637,12 @@ class _EditUserInfoPage2State extends State<EditUserInfoPage2>
|
||||
child: text(value, textColor: Colors.white, fontSize: 15.sp),
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
Icons.keyboard_arrow_right,
|
||||
size: 20.w,
|
||||
color: Colors.white70,
|
||||
),
|
||||
if (func != null)
|
||||
Icon(
|
||||
Icons.keyboard_arrow_right,
|
||||
size: 20.w,
|
||||
color: Colors.white70,
|
||||
),
|
||||
SizedBox(width: 8.w),
|
||||
],
|
||||
),
|
||||
@ -656,7 +656,7 @@ class _EditUserInfoPage2State extends State<EditUserInfoPage2>
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
func.call();
|
||||
func?.call();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@ -109,13 +109,25 @@ class _PersonDetailPageState extends State<PersonDetailPage> with RouteAware {
|
||||
}
|
||||
});
|
||||
|
||||
Provider.of<SocialChatUserProfileManager>(context, listen: false)
|
||||
.userProfile = null;
|
||||
Provider.of<SocialChatUserProfileManager>(
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
_loadInitialProfileData();
|
||||
});
|
||||
}
|
||||
|
||||
void _loadInitialProfileData() {
|
||||
final profileManager = Provider.of<SocialChatUserProfileManager>(
|
||||
context,
|
||||
listen: false,
|
||||
).getUserInfoById(widget.tageId);
|
||||
);
|
||||
profileManager.userProfile = null;
|
||||
profileManager.getUserInfoById(widget.tageId);
|
||||
SCAccountRepository().userIdentity(userId: widget.tageId).then((v) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
userIdentity = v;
|
||||
setState(() {});
|
||||
});
|
||||
@ -123,11 +135,17 @@ class _PersonDetailPageState extends State<PersonDetailPage> with RouteAware {
|
||||
SCAccountRepository()
|
||||
.followCheck(widget.tageId)
|
||||
.then((v) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
isFollow = v;
|
||||
isLoading = false;
|
||||
setState(() {});
|
||||
})
|
||||
.catchError((e) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
@ -135,6 +153,9 @@ class _PersonDetailPageState extends State<PersonDetailPage> with RouteAware {
|
||||
SCAccountRepository()
|
||||
.blacklistCheck(widget.tageId)
|
||||
.then((v) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
isBlacklist = v;
|
||||
isBlacklistLoading = false;
|
||||
setState(() {});
|
||||
@ -145,6 +166,9 @@ class _PersonDetailPageState extends State<PersonDetailPage> with RouteAware {
|
||||
}
|
||||
})
|
||||
.catchError((e) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
isBlacklistLoading = false;
|
||||
});
|
||||
@ -1564,7 +1588,7 @@ class _PersonDetailPageState extends State<PersonDetailPage> with RouteAware {
|
||||
if (payload.rightUserId.trim().isEmpty) {
|
||||
return;
|
||||
}
|
||||
final cancelText = SCAppLocalizations.of(context)!.cancel;
|
||||
const cancelText = 'unbing';
|
||||
SCLoadingManager.show(context: context);
|
||||
late final _ProfileRelationProgressData progress;
|
||||
try {
|
||||
@ -1668,6 +1692,15 @@ class _PersonDetailPageState extends State<PersonDetailPage> with RouteAware {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
final profileManager = Provider.of<SocialChatUserProfileManager>(
|
||||
context,
|
||||
listen: false,
|
||||
);
|
||||
profileManager.removeLoadedCpRelation(
|
||||
userId: payload.leftUserId,
|
||||
peerUserId: partnerUserId,
|
||||
relationType: payload.relationType,
|
||||
);
|
||||
Provider.of<RtcProvider?>(
|
||||
context,
|
||||
listen: false,
|
||||
@ -1676,10 +1709,12 @@ class _PersonDetailPageState extends State<PersonDetailPage> with RouteAware {
|
||||
peerUserId: partnerUserId,
|
||||
relationType: payload.relationType,
|
||||
);
|
||||
await Provider.of<SocialChatUserProfileManager>(
|
||||
context,
|
||||
listen: false,
|
||||
).refreshLoadedCpProfiles();
|
||||
await profileManager.refreshLoadedCpProfiles();
|
||||
profileManager.removeLoadedCpRelation(
|
||||
userId: payload.leftUserId,
|
||||
peerUserId: partnerUserId,
|
||||
relationType: payload.relationType,
|
||||
);
|
||||
await SmartDialog.dismiss(tag: RoomCpProgressDialog.dialogTag);
|
||||
SCTts.show(l10n.operationSuccessful);
|
||||
} catch (_) {
|
||||
@ -2693,7 +2728,21 @@ class _PersonDetailPageState extends State<PersonDetailPage> with RouteAware {
|
||||
ref.userProfile?.id ?? "",
|
||||
relationType: cpRelation?.relationType ?? "CP",
|
||||
)
|
||||
.then((result) {
|
||||
.then((result) async {
|
||||
final currentUserId =
|
||||
AccountStorage()
|
||||
.getCurrentUser()
|
||||
?.userProfile
|
||||
?.id
|
||||
?.trim() ??
|
||||
"";
|
||||
final profileUserId =
|
||||
ref.userProfile?.id?.trim() ?? "";
|
||||
ref.removeLoadedCpRelation(
|
||||
userId: currentUserId,
|
||||
peerUserId: profileUserId,
|
||||
relationType: cpRelation?.relationType ?? "CP",
|
||||
);
|
||||
if (mounted) {
|
||||
Provider.of<RtcProvider?>(
|
||||
context,
|
||||
@ -2708,7 +2757,12 @@ class _PersonDetailPageState extends State<PersonDetailPage> with RouteAware {
|
||||
relationType: cpRelation?.relationType ?? "CP",
|
||||
);
|
||||
}
|
||||
ref.refreshLoadedCpProfiles();
|
||||
await ref.refreshLoadedCpProfiles();
|
||||
ref.removeLoadedCpRelation(
|
||||
userId: currentUserId,
|
||||
peerUserId: profileUserId,
|
||||
relationType: cpRelation?.relationType ?? "CP",
|
||||
);
|
||||
SmartDialog.dismiss(tag: "showPartWaysDialog");
|
||||
SCTts.show(
|
||||
SCAppLocalizations.of(
|
||||
|
||||
@ -9,7 +9,6 @@ import 'package:yumi/app/constants/sc_room_msg_type.dart';
|
||||
import 'package:yumi/shared/tools/sc_permission_utils.dart';
|
||||
import 'package:yumi/shared/tools/sc_room_utils.dart';
|
||||
import 'package:yumi/shared/tools/sc_room_top_layer_guard.dart';
|
||||
import 'package:yumi/shared/tools/sc_cp_relation_level_utils.dart';
|
||||
import 'package:yumi/shared/tools/sc_cp_relation_notice_utils.dart';
|
||||
import 'package:yumi/shared/data_sources/models/message/room_rocket_launch_broadcast_message.dart';
|
||||
import 'package:yumi/shared/data_sources/models/message/sc_floating_message.dart';
|
||||
@ -1833,31 +1832,23 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
||||
final closeFriendPairs = <CPRes>[];
|
||||
await Future.wait(
|
||||
_roomMicRelationTypes.map((relationType) async {
|
||||
final cabin = await _safeLoadRoomMicRelationCabin(userId, relationType);
|
||||
final pair = cabin?.cpPairUserProfileCO;
|
||||
if (!_hasRoomMicRelationPair(pair)) {
|
||||
return;
|
||||
}
|
||||
final normalizedType = scNormalizeCpRelationType(
|
||||
pair?.relationType ?? relationType,
|
||||
);
|
||||
final enrichedPair = pair!.copyWith(
|
||||
relationType: normalizedType,
|
||||
cpValue: pair.cpValue ?? cabin?.cpVal?.toDouble(),
|
||||
levelText:
|
||||
scCpRelationLevelTextFromCabin(
|
||||
cabin,
|
||||
fallbackText: pair.levelText,
|
||||
) ??
|
||||
_roomMicRelationLevelTextFromCabin(cabin),
|
||||
);
|
||||
if (_isRoomMicRelationLocallyDismissed(enrichedPair)) {
|
||||
return;
|
||||
}
|
||||
if (normalizedType == "CP") {
|
||||
cpPairs.add(enrichedPair);
|
||||
} else {
|
||||
closeFriendPairs.add(enrichedPair);
|
||||
final pairs = await _safeLoadRoomMicRelationPairs(userId, relationType);
|
||||
for (final pair in pairs) {
|
||||
if (!_hasRoomMicRelationPair(pair)) {
|
||||
continue;
|
||||
}
|
||||
final normalizedType = scNormalizeCpRelationType(
|
||||
pair.relationType ?? relationType,
|
||||
);
|
||||
final enrichedPair = pair.copyWith(relationType: normalizedType);
|
||||
if (_isRoomMicRelationLocallyDismissed(enrichedPair)) {
|
||||
continue;
|
||||
}
|
||||
if (normalizedType == "CP") {
|
||||
cpPairs.add(enrichedPair);
|
||||
} else {
|
||||
closeFriendPairs.add(enrichedPair);
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
@ -1868,53 +1859,26 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
||||
);
|
||||
}
|
||||
|
||||
Future<SCCpCabinRes?> _safeLoadRoomMicRelationCabin(
|
||||
Future<List<CPRes>> _safeLoadRoomMicRelationPairs(
|
||||
String userId,
|
||||
String relationType,
|
||||
) async {
|
||||
try {
|
||||
return await SCAccountRepository().cpCabin(
|
||||
userId,
|
||||
return await SCAccountRepository().cpRelationshipPairs(
|
||||
userId: userId,
|
||||
relationType: relationType,
|
||||
);
|
||||
} catch (error) {
|
||||
if (kDebugMode) {
|
||||
debugPrint(
|
||||
"[CP][MicRelation] cabin failed userId=$userId "
|
||||
"[CP][MicRelation] pair failed userId=$userId "
|
||||
"relationType=$relationType error=$error",
|
||||
);
|
||||
}
|
||||
return null;
|
||||
return const <CPRes>[];
|
||||
}
|
||||
}
|
||||
|
||||
String? _roomMicRelationLevelTextFromCabin(SCCpCabinRes? cabin) {
|
||||
final config = cabin?.currentCpCabinConfigCO;
|
||||
if (config is! Map) {
|
||||
return null;
|
||||
}
|
||||
final level = _firstRoomMicRelationConfigText([
|
||||
config["level"],
|
||||
config["cpLevel"],
|
||||
config["cabinLevel"],
|
||||
config["lv"],
|
||||
]);
|
||||
if (level.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
return "Lv.$level";
|
||||
}
|
||||
|
||||
String _firstRoomMicRelationConfigText(Iterable<dynamic> values) {
|
||||
for (final value in values) {
|
||||
final text = value?.toString().trim() ?? "";
|
||||
if (text.isNotEmpty) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void _applyHydratedRoomMicRelationProfile(
|
||||
String roomId,
|
||||
String userId,
|
||||
|
||||
@ -6338,7 +6338,8 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
'giftId=${gift.id} giftName=${gift.giftName}',
|
||||
);
|
||||
SCGiftVapSvgaManager().play(giftSourceUrl);
|
||||
} else if (SCGlobalConfig.isLowPerformanceDevice &&
|
||||
} else if (!scIsCpGift(gift) &&
|
||||
SCGlobalConfig.isLowPerformanceDevice &&
|
||||
SCGlobalConfig.isGiftSpecialEffects &&
|
||||
rtcProvider.shouldShowRoomVisualEffects) {
|
||||
final roomId =
|
||||
@ -6414,7 +6415,7 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
);
|
||||
}
|
||||
final coins = (msg.number ?? 0) * (gift.giftCandy ?? 0);
|
||||
if (coins > 9999) {
|
||||
if (coins > 9999 && !scIsCpGift(gift)) {
|
||||
_enqueueGiftFloatingMessage(
|
||||
SCFloatingMessage(
|
||||
type: 1,
|
||||
|
||||
@ -210,6 +210,7 @@ class SocialChatUserProfileManager extends ChangeNotifier {
|
||||
RoomUserCardRes? userCardInfo;
|
||||
Object? userCardLoadError;
|
||||
bool isUserCardLoading = false;
|
||||
bool isUserCardRelationLoading = false;
|
||||
int _userCardRequestSerial = 0;
|
||||
int _userCardSessionSerial = 0;
|
||||
int? _activeUserCardSessionSerial;
|
||||
@ -235,6 +236,7 @@ class SocialChatUserProfileManager extends ChangeNotifier {
|
||||
userCardInfo = null;
|
||||
userCardLoadError = null;
|
||||
isUserCardLoading = true;
|
||||
isUserCardRelationLoading = false;
|
||||
notifyListeners();
|
||||
|
||||
if (normalizedUserId.isEmpty) {
|
||||
@ -257,6 +259,7 @@ class SocialChatUserProfileManager extends ChangeNotifier {
|
||||
userCardInfo = card;
|
||||
userCardLoadError = null;
|
||||
isUserCardLoading = false;
|
||||
isUserCardRelationLoading = card.userProfile != null;
|
||||
notifyListeners();
|
||||
unawaited(
|
||||
_hydrateRoomUserCard(
|
||||
@ -325,8 +328,14 @@ class SocialChatUserProfileManager extends ChangeNotifier {
|
||||
}
|
||||
userCardInfo = hydratedCard;
|
||||
userCardLoadError = null;
|
||||
isUserCardRelationLoading = false;
|
||||
notifyListeners();
|
||||
} catch (error, stackTrace) {
|
||||
if (requestSerial == _userCardRequestSerial &&
|
||||
sessionSerial == _activeUserCardSessionSerial) {
|
||||
isUserCardRelationLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
_debugProfileLoadFailure(
|
||||
scope: 'roomCardHydrate',
|
||||
userId: userId,
|
||||
@ -346,6 +355,7 @@ class SocialChatUserProfileManager extends ChangeNotifier {
|
||||
userCardInfo = null;
|
||||
userCardLoadError = null;
|
||||
isUserCardLoading = false;
|
||||
isUserCardRelationLoading = false;
|
||||
}
|
||||
|
||||
Future<RoomUserCardRes?> _withCurrentVipLevelForCard(
|
||||
@ -357,7 +367,7 @@ class SocialChatUserProfileManager extends ChangeNotifier {
|
||||
return card;
|
||||
}
|
||||
var mergedProfile = await _withCurrentVipLevel(profile, userId);
|
||||
mergedProfile = await _withCpRelationshipProfiles(mergedProfile, userId);
|
||||
mergedProfile = await _withCpCabinProfiles(mergedProfile, userId);
|
||||
if (mergedProfile == profile) {
|
||||
return card;
|
||||
}
|
||||
@ -487,44 +497,6 @@ 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,
|
||||
@ -953,6 +925,127 @@ class SocialChatUserProfileManager extends ChangeNotifier {
|
||||
await _refreshLoadedCpProfilesForUserIds(normalizedUserIds);
|
||||
}
|
||||
|
||||
void removeLoadedCpRelation({
|
||||
required String userId,
|
||||
required String peerUserId,
|
||||
required String relationType,
|
||||
}) {
|
||||
final normalizedUserId = userId.trim();
|
||||
final normalizedPeerUserId = peerUserId.trim();
|
||||
final normalizedRelationType = _normalizeCpRelationType(relationType);
|
||||
if (normalizedUserId.isEmpty ||
|
||||
normalizedPeerUserId.isEmpty ||
|
||||
normalizedRelationType.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
var changed = false;
|
||||
final currentProfile = currentUserProfile;
|
||||
if (currentProfile != null) {
|
||||
final nextCurrentProfile = _profileWithoutCpRelation(
|
||||
currentProfile,
|
||||
userId: normalizedUserId,
|
||||
peerUserId: normalizedPeerUserId,
|
||||
relationType: normalizedRelationType,
|
||||
);
|
||||
if (!identical(nextCurrentProfile, currentProfile)) {
|
||||
final currentUser = AccountStorage().getCurrentUser();
|
||||
currentUser?.setUserProfile(nextCurrentProfile);
|
||||
if (currentUser != null) {
|
||||
AccountStorage().setCurrentUser(currentUser);
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
final detailProfile = userProfile;
|
||||
if (detailProfile != null) {
|
||||
final nextDetailProfile = _profileWithoutCpRelation(
|
||||
detailProfile,
|
||||
userId: normalizedUserId,
|
||||
peerUserId: normalizedPeerUserId,
|
||||
relationType: normalizedRelationType,
|
||||
);
|
||||
if (!identical(nextDetailProfile, detailProfile)) {
|
||||
userProfile = nextDetailProfile;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
final cardProfile = userCardInfo?.userProfile;
|
||||
if (cardProfile != null) {
|
||||
final nextCardProfile = _profileWithoutCpRelation(
|
||||
cardProfile,
|
||||
userId: normalizedUserId,
|
||||
peerUserId: normalizedPeerUserId,
|
||||
relationType: normalizedRelationType,
|
||||
);
|
||||
if (!identical(nextCardProfile, cardProfile)) {
|
||||
userCardInfo = userCardInfo?.copyWith(userProfile: nextCardProfile);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
SocialChatUserProfile _profileWithoutCpRelation(
|
||||
SocialChatUserProfile profile, {
|
||||
required String userId,
|
||||
required String peerUserId,
|
||||
required String relationType,
|
||||
}) {
|
||||
var changed = false;
|
||||
List<CPRes>? filterRelations(List<CPRes>? relations) {
|
||||
if (relations == null) {
|
||||
return null;
|
||||
}
|
||||
final filtered =
|
||||
relations.where((relation) {
|
||||
return !_matchesCpRelation(
|
||||
relation,
|
||||
userId: userId,
|
||||
peerUserId: peerUserId,
|
||||
relationType: relationType,
|
||||
);
|
||||
}).toList();
|
||||
if (filtered.length != relations.length) {
|
||||
changed = true;
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
final nextCpList = filterRelations(profile.cpList);
|
||||
final nextCloseFriendList = filterRelations(profile.closeFriendList);
|
||||
if (!changed) {
|
||||
return profile;
|
||||
}
|
||||
return profile.copyWith(
|
||||
cpList: nextCpList,
|
||||
closeFriendList: nextCloseFriendList,
|
||||
isCpRelation: nextCpList?.isNotEmpty == true,
|
||||
);
|
||||
}
|
||||
|
||||
bool _matchesCpRelation(
|
||||
CPRes relation, {
|
||||
required String userId,
|
||||
required String peerUserId,
|
||||
required String relationType,
|
||||
}) {
|
||||
if (_normalizeCpRelationType(relation.relationType) != relationType) {
|
||||
return false;
|
||||
}
|
||||
final relationUserIds = <String>{
|
||||
relation.meUserId?.trim() ?? "",
|
||||
relation.cpUserId?.trim() ?? "",
|
||||
}..remove("");
|
||||
return relationUserIds.contains(userId) &&
|
||||
relationUserIds.contains(peerUserId);
|
||||
}
|
||||
|
||||
Future<void> _refreshLoadedCpProfilesForUserIds(Set<String>? userIds) async {
|
||||
String refreshedUserId(String? userId) {
|
||||
final normalizedUserId = userId?.trim() ?? "";
|
||||
@ -981,7 +1074,7 @@ class SocialChatUserProfileManager extends ChangeNotifier {
|
||||
final cardUserId = refreshedUserId(cardProfile?.id);
|
||||
if (userCardInfo != null && cardProfile != null && cardUserId.isNotEmpty) {
|
||||
userCardInfo = userCardInfo?.copyWith(
|
||||
userProfile: await _withCpRelationshipProfiles(cardProfile, cardUserId),
|
||||
userProfile: await _withCpCabinProfiles(cardProfile, cardUserId),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,90 @@
|
||||
class SCCpGiftRelationCheckRes {
|
||||
const SCCpGiftRelationCheckRes({
|
||||
this.status = true,
|
||||
this.msg = '',
|
||||
this.relationType = '',
|
||||
this.userId = '',
|
||||
this.acceptUserId = '',
|
||||
this.userRelationCount = 0,
|
||||
this.acceptUserRelationCount = 0,
|
||||
this.maxRelationCount = 0,
|
||||
this.userRelationFull = false,
|
||||
this.acceptUserRelationFull = false,
|
||||
});
|
||||
|
||||
factory SCCpGiftRelationCheckRes.fromJson(dynamic json) {
|
||||
final source =
|
||||
json is Map
|
||||
? json.map((key, value) => MapEntry(key.toString(), value))
|
||||
: const <String, dynamic>{};
|
||||
return SCCpGiftRelationCheckRes(
|
||||
status: _asBool(source['status']) ?? true,
|
||||
msg: source['msg']?.toString() ?? '',
|
||||
relationType: source['relationType']?.toString() ?? '',
|
||||
userId: source['userId']?.toString() ?? '',
|
||||
acceptUserId: source['acceptUserId']?.toString() ?? '',
|
||||
userRelationCount: _asInt(source['userRelationCount']) ?? 0,
|
||||
acceptUserRelationCount: _asInt(source['acceptUserRelationCount']) ?? 0,
|
||||
maxRelationCount: _asInt(source['maxRelationCount']) ?? 0,
|
||||
userRelationFull: _asBool(source['userRelationFull']) ?? false,
|
||||
acceptUserRelationFull:
|
||||
_asBool(source['acceptUserRelationFull']) ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
final bool status;
|
||||
final String msg;
|
||||
final String relationType;
|
||||
final String userId;
|
||||
final String acceptUserId;
|
||||
final int userRelationCount;
|
||||
final int acceptUserRelationCount;
|
||||
final int maxRelationCount;
|
||||
final bool userRelationFull;
|
||||
final bool acceptUserRelationFull;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'status': status,
|
||||
'msg': msg,
|
||||
'relationType': relationType,
|
||||
'userId': userId,
|
||||
'acceptUserId': acceptUserId,
|
||||
'userRelationCount': userRelationCount,
|
||||
'acceptUserRelationCount': acceptUserRelationCount,
|
||||
'maxRelationCount': maxRelationCount,
|
||||
'userRelationFull': userRelationFull,
|
||||
'acceptUserRelationFull': acceptUserRelationFull,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
bool? _asBool(dynamic value) {
|
||||
if (value is bool) {
|
||||
return value;
|
||||
}
|
||||
if (value is num) {
|
||||
return value != 0;
|
||||
}
|
||||
final text = value?.toString().trim().toLowerCase() ?? '';
|
||||
if (text.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
if (text == 'true' || text == '1' || text == 'yes') {
|
||||
return true;
|
||||
}
|
||||
if (text == 'false' || text == '0' || text == 'no') {
|
||||
return false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
int? _asInt(dynamic value) {
|
||||
if (value is int) {
|
||||
return value;
|
||||
}
|
||||
if (value is num) {
|
||||
return value.toInt();
|
||||
}
|
||||
return int.tryParse(value?.toString() ?? '');
|
||||
}
|
||||
@ -29,6 +29,7 @@ import 'package:yumi/shared/business_logic/models/res/sc_user_red_packet_grab_re
|
||||
import 'package:yumi/shared/business_logic/models/res/sc_user_red_packet_send_res.dart';
|
||||
import 'package:yumi/shared/business_logic/models/res/sc_violation_handle_res.dart';
|
||||
import 'package:yumi/shared/business_logic/models/res/sc_cp_rights_config_res.dart';
|
||||
import 'package:yumi/shared/business_logic/models/res/sc_cp_gift_relation_check_res.dart';
|
||||
|
||||
abstract class SocialChatUserRepository {
|
||||
Future<SocialChatLoginRes> getUser(String id);
|
||||
@ -329,6 +330,12 @@ abstract class SocialChatUserRepository {
|
||||
///查询 CP 小屋
|
||||
Future<SCCpCabinRes> cpCabin(String userId, {String relationType = 'CP'});
|
||||
|
||||
///CP 礼物关系名额校验
|
||||
Future<SCCpGiftRelationCheckRes> cpGiftRelationCheck({
|
||||
required String acceptUserId,
|
||||
String relationType = 'CP',
|
||||
});
|
||||
|
||||
///查询 CP 值
|
||||
Future<SCCpCabinValueRes> cpCabinValue(
|
||||
String userId, {
|
||||
|
||||
@ -9,6 +9,7 @@ import 'package:yumi/shared/business_logic/models/res/sc_prop_coupon_record_list
|
||||
import 'package:yumi/shared/business_logic/models/res/sc_public_message_page_res.dart';
|
||||
import 'package:yumi/shared/business_logic/models/res/room_res.dart'
|
||||
hide WearBadge;
|
||||
import 'package:yumi/shared/business_logic/models/res/sc_cp_gift_relation_check_res.dart';
|
||||
import 'package:yumi/shared/business_logic/models/res/sc_cp_rights_config_res.dart';
|
||||
import 'package:yumi/shared/business_logic/models/res/sc_task_list_res.dart';
|
||||
import 'package:yumi/shared/business_logic/models/res/sc_user_counter_res.dart';
|
||||
@ -1516,6 +1517,34 @@ class SCAccountRepository implements SocialChatUserRepository {
|
||||
}
|
||||
}
|
||||
|
||||
///user/cp-relationship/gift-relation/check
|
||||
@override
|
||||
Future<SCCpGiftRelationCheckRes> cpGiftRelationCheck({
|
||||
required String acceptUserId,
|
||||
String relationType = 'CP',
|
||||
}) async {
|
||||
final query = {"acceptUserId": acceptUserId, "relationType": relationType};
|
||||
_cpDebugLog('giftRelationCheck request query=$query');
|
||||
try {
|
||||
final result = await http.get<SCCpGiftRelationCheckRes>(
|
||||
"/user/cp-relationship/gift-relation/check",
|
||||
queryParams: query,
|
||||
extra: const {BaseNetworkClient.silentErrorToastKey: true},
|
||||
fromJson: SCCpGiftRelationCheckRes.fromJson,
|
||||
);
|
||||
_cpDebugLog(
|
||||
'giftRelationCheck response query=$query '
|
||||
'status=${result.status} msg=${result.msg} '
|
||||
'userFull=${result.userRelationFull} '
|
||||
'acceptFull=${result.acceptUserRelationFull}',
|
||||
);
|
||||
return result;
|
||||
} catch (error) {
|
||||
_cpDebugLog('giftRelationCheck failed query=$query error=$error');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
///user/cp/cabin
|
||||
@override
|
||||
Future<SCCpCabinRes> cpCabin(
|
||||
|
||||
@ -37,7 +37,7 @@ class RoomCpProgressDialog extends StatelessWidget {
|
||||
this.targetValue = 1,
|
||||
this.expAwayText = '0',
|
||||
this.nextLevelText = 'Lv. 1',
|
||||
this.cancelText = 'Cancel',
|
||||
this.cancelText = 'unbing',
|
||||
this.dismissTag = dialogTag,
|
||||
this.onCancel,
|
||||
});
|
||||
@ -68,7 +68,7 @@ class RoomCpProgressDialog extends StatelessWidget {
|
||||
double targetValue = 1,
|
||||
String expAwayText = '0',
|
||||
String nextLevelText = 'Lv. 1',
|
||||
String cancelText = 'Cancel',
|
||||
String cancelText = 'unbing',
|
||||
String dismissTag = dialogTag,
|
||||
VoidCallback? onCancel,
|
||||
}) async {
|
||||
@ -495,7 +495,7 @@ class _CancelButton extends StatelessWidget {
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
Text(
|
||||
text.trim().isEmpty ? 'Cancel' : text.trim(),
|
||||
text.trim().isEmpty ? 'unbing' : text.trim(),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.center,
|
||||
|
||||
@ -76,7 +76,12 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
|
||||
context,
|
||||
listen: false,
|
||||
);
|
||||
_loadRoomUserCard();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
_loadRoomUserCard();
|
||||
});
|
||||
SCAccountRepository().userIdentity(userId: widget.userId).then((v) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
@ -139,7 +144,11 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
|
||||
|
||||
final profile = ref.userCardInfo?.userProfile;
|
||||
final dataCard = _activeDataCard(ref.userCardInfo);
|
||||
final sheetHeight = _resolvedProfileSheetHeight(screenHeight, profile);
|
||||
final sheetHeight = _resolvedProfileSheetHeight(
|
||||
screenHeight,
|
||||
profile,
|
||||
relationLoading: ref.isUserCardRelationLoading,
|
||||
);
|
||||
|
||||
return _buildProfileSheet(
|
||||
context: context,
|
||||
@ -231,9 +240,13 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
|
||||
|
||||
double _resolvedProfileSheetHeight(
|
||||
double screenHeight,
|
||||
SocialChatUserProfile? profile,
|
||||
) {
|
||||
SocialChatUserProfile? profile, {
|
||||
required bool relationLoading,
|
||||
}) {
|
||||
final defaultSheetHeight = screenHeight * _profileSheetHeightFactor;
|
||||
if (relationLoading) {
|
||||
return defaultSheetHeight;
|
||||
}
|
||||
final hasCpRelation = _hasCpRelation(profile);
|
||||
final hasCloseFriends = _closeFriendProfileData(profile).isNotEmpty;
|
||||
var resolvedHeight = defaultSheetHeight;
|
||||
@ -356,6 +369,7 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
|
||||
}) {
|
||||
final hasCpRelation = _hasCpRelation(profile);
|
||||
final closeFriends = _closeFriendProfileData(profile);
|
||||
final isRelationLoading = ref.isUserCardRelationLoading;
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
@ -386,7 +400,12 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
|
||||
ref,
|
||||
profile,
|
||||
),
|
||||
if (hasCpRelation) ...[
|
||||
if (isRelationLoading) ...[
|
||||
SizedBox(height: 12.w),
|
||||
_buildCpRelationSkeletonCard(),
|
||||
SizedBox(height: 11.w),
|
||||
_buildCloseFriendSkeletonStrip(),
|
||||
] else if (hasCpRelation) ...[
|
||||
SizedBox(height: 12.w),
|
||||
_buildCpRelationCard(
|
||||
context: context,
|
||||
@ -400,7 +419,9 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
|
||||
],
|
||||
SizedBox(
|
||||
height:
|
||||
hasCpRelation || closeFriends.isNotEmpty
|
||||
isRelationLoading ||
|
||||
hasCpRelation ||
|
||||
closeFriends.isNotEmpty
|
||||
? 14.w
|
||||
: 12.w,
|
||||
),
|
||||
@ -691,6 +712,51 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCpRelationSkeletonCard() {
|
||||
return SizedBox(
|
||||
height: 114.w,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: 0.10),
|
||||
borderRadius: BorderRadius.circular(12.w),
|
||||
border: Border.all(color: Colors.white.withValues(alpha: 0.12)),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
left: 39.w,
|
||||
top: 26.w,
|
||||
child: _buildSkeletonCircle(60.w),
|
||||
),
|
||||
Positioned(
|
||||
right: 38.w,
|
||||
top: 26.w,
|
||||
child: _buildSkeletonCircle(60.w),
|
||||
),
|
||||
Positioned(
|
||||
left: 142.w,
|
||||
right: 142.w,
|
||||
top: 28.w,
|
||||
child: _buildSkeletonBlock(height: 18.w, radius: 9.w),
|
||||
),
|
||||
Positioned(
|
||||
left: 156.w,
|
||||
right: 156.w,
|
||||
top: 54.w,
|
||||
child: _buildSkeletonBlock(height: 10.w, radius: 5.w),
|
||||
),
|
||||
Positioned(
|
||||
left: 118.w,
|
||||
right: 118.w,
|
||||
top: 80.w,
|
||||
child: _buildSkeletonBlock(height: 14.w, radius: 7.w),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCpCardText(
|
||||
String value, {
|
||||
required Color color,
|
||||
@ -791,6 +857,69 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCloseFriendSkeletonStrip() {
|
||||
return SizedBox(
|
||||
height: 41.w,
|
||||
width: double.infinity,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: 0.10),
|
||||
borderRadius: BorderRadius.circular(12.w),
|
||||
border: Border.all(color: Colors.white.withValues(alpha: 0.12)),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
PositionedDirectional(
|
||||
top: 13.w,
|
||||
start: 16.w,
|
||||
width: 118.w,
|
||||
child: _buildSkeletonBlock(height: 14.w, radius: 7.w),
|
||||
),
|
||||
PositionedDirectional(
|
||||
top: 8.w,
|
||||
end: 13.w,
|
||||
child: SizedBox(
|
||||
height: 25.w,
|
||||
width: 112.w,
|
||||
child: Stack(
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
children: [
|
||||
for (var index = 0; index < 4; index++)
|
||||
PositionedDirectional(
|
||||
end: (3 - index) * 17.w,
|
||||
child: _buildSkeletonCircle(25.w),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSkeletonBlock({required double height, required double radius}) {
|
||||
return Container(
|
||||
height: height,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: 0.22),
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSkeletonCircle(double size) {
|
||||
return Container(
|
||||
width: size,
|
||||
height: size,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.white.withValues(alpha: 0.22),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_RoomProfileCpData _cpProfileData(SocialChatUserProfile? profile) {
|
||||
final currentProfile = AccountStorage().getCurrentUser()?.userProfile;
|
||||
final cp = _firstRelation(
|
||||
@ -1432,8 +1561,15 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
|
||||
void _openProfile(BuildContext context) {
|
||||
final route =
|
||||
"${SCMainRoute.person}?isMe=${AccountStorage().getCurrentUser()?.userProfile?.id == widget.userId}&tageId=${widget.userId}";
|
||||
final rootContext = navigatorKey.currentState?.context;
|
||||
Navigator.of(context).pop();
|
||||
SCNavigatorUtils.push(navigatorKey.currentState?.context ?? context, route);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
final targetContext = navigatorKey.currentState?.context ?? rootContext;
|
||||
if (targetContext == null) {
|
||||
return;
|
||||
}
|
||||
SCNavigatorUtils.push(targetContext, route);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _openChat(BuildContext context) async {
|
||||
@ -1497,7 +1633,7 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
|
||||
SocialChatUserProfile? profile,
|
||||
) async {
|
||||
final cp = _cpProfileData(profile);
|
||||
final cancelText = SCAppLocalizations.of(context)!.cancel;
|
||||
const cancelText = 'unbing';
|
||||
SCLoadingManager.show();
|
||||
late final _RoomCpProgressData progress;
|
||||
try {
|
||||
|
||||
@ -21,4 +21,24 @@ void main() {
|
||||
|
||||
expect(manager.userCardInfo, isNull);
|
||||
});
|
||||
|
||||
test('removeLoadedCpRelation removes matching close friend relation', () {
|
||||
final manager = SocialChatUserProfileManager();
|
||||
manager.userProfile = SocialChatUserProfile(
|
||||
id: '100',
|
||||
closeFriendList: [
|
||||
CPRes(meUserId: '100', cpUserId: '200', relationType: 'BROTHER'),
|
||||
CPRes(meUserId: '100', cpUserId: '300', relationType: 'SISTERS'),
|
||||
],
|
||||
);
|
||||
|
||||
manager.removeLoadedCpRelation(
|
||||
userId: '100',
|
||||
peerUserId: '200',
|
||||
relationType: 'BROTHER',
|
||||
);
|
||||
|
||||
expect(manager.userProfile?.closeFriendList, hasLength(1));
|
||||
expect(manager.userProfile?.closeFriendList?.single.cpUserId, '300');
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user