From 07624ac105deb0c6e3edd9096d452f44488487c3 Mon Sep 17 00:00:00 2001 From: zhx Date: Mon, 25 May 2026 20:57:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8D=A1=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/modules/chat/message_chat_page.dart | 101 ++++++++++++++---- .../room/cp/room_cp_invite_dialog.dart | 8 ++ 2 files changed, 91 insertions(+), 18 deletions(-) diff --git a/lib/modules/chat/message_chat_page.dart b/lib/modules/chat/message_chat_page.dart index aa19a22..f24c035 100644 --- a/lib/modules/chat/message_chat_page.dart +++ b/lib/modules/chat/message_chat_page.dart @@ -1252,8 +1252,11 @@ class _MessageItem extends StatelessWidget { } final isCpInviteMessage = customData != null && _isCpInvitePayload(customData); + final isExplicitCpResultMessage = + isCpInviteMessage && + _cpInviteStateFromData(customData) != _CpInviteMessageState.pending; final cpRelationFormedCard = - isCpInviteMessage ? null : _cpRelationFormedMessageCard(); + isExplicitCpResultMessage ? _cpRelationFormedMessageCard() : null; final cpStatusLineText = _cpStatusLineTextForMessage(); return Container( margin: EdgeInsets.symmetric(horizontal: 15.w, vertical: 8.w), @@ -1307,7 +1310,8 @@ class _MessageItem extends StatelessWidget { ), child: cpRelationFormedCard, ) - else if (cpStatusLineText == null || isCpInviteMessage) + else if (cpStatusLineText == null || + (isCpInviteMessage && !isExplicitCpResultMessage)) Padding( padding: EdgeInsets.only( top: cpStatusLineText == null ? 0 : 10.w, @@ -1566,7 +1570,7 @@ class _MessageItem extends StatelessWidget { if (data == null || !_isCpInvitePayload(data)) { return null; } - if (_cpInviteStateForMessage(data) != _CpInviteMessageState.accepted) { + if (_cpInviteStateFromData(data) != _CpInviteMessageState.accepted) { return null; } final cpInvite = _cpInviteFromMessageData(data); @@ -1714,7 +1718,7 @@ class _MessageItem extends StatelessWidget { final localizations = SCAppLocalizations.of(context)!; final relationType = _cpRelationTypeFromMessageData(data); if (state == _CpInviteMessageState.accepted) { - return _cpAcceptedStatusLineText(relationType); + return null; } if (state == _CpInviteMessageState.expired) { if (relationType != "CP") { @@ -1733,19 +1737,34 @@ class _MessageItem extends StatelessWidget { : "You declined the other party's $relationLabel invitation."; } - String _cpAcceptedStatusLineText(String relationType) { - final localizations = SCAppLocalizations.of(context)!; - switch (scNormalizeCpRelationType(relationType)) { - case "BROTHER": - return "Have become sworn brothers"; - case "SISTERS": - return "Have become sisters"; - case "CP": - default: - return localizations.closeFriendsHaveBecome; + String? _cpInviteDialogStatusText( + Map data, + RoomCpInviteActionState actionState, + ) { + switch (actionState) { + case RoomCpInviteActionState.rejected: + return _cpRejectedStatusText(data); + case RoomCpInviteActionState.expired: + case RoomCpInviteActionState.accepted: + case RoomCpInviteActionState.pending: + return null; } } + String _cpRejectedStatusText(Map data) { + final localizations = SCAppLocalizations.of(context)!; + final relationType = _cpRelationTypeFromMessageData(data); + if (relationType == "CP") { + return _isCurrentUserCpInviter(data) + ? localizations.otherDeclinedCloseFriendInvite + : localizations.youDeclinedCloseFriendInvite; + } + final relationLabel = scCpRelationPossessiveLabel(relationType); + return _isCurrentUserCpInviter(data) + ? "The other party declined your $relationLabel invitation." + : "You declined the other party's $relationLabel invitation."; + } + void _showCpInviteDialogFromMessage( Map data, SCSystemInvitMessageRes? cpInvite, @@ -1896,6 +1915,7 @@ class _MessageItem extends StatelessWidget { actionState: effectiveActionState, countdownSeconds: _cpInviteSecondsLeft(data), descriptionText: _cpInviteDescriptionText(relationType), + statusText: _cpInviteDialogStatusText(data, effectiveActionState), onAccept: !isInviter && cpInvite != null && @@ -2097,22 +2117,64 @@ class _MessageItem extends StatelessWidget { return currentState; } final currentTimestamp = message.timestamp ?? 0; + var hasAcceptedSiblingInvite = false; for (final item in currentConversationMessageList) { if ((item.timestamp ?? 0) < currentTimestamp) { continue; } final data = _customDataFromMessage(item); - if (data == null || _cpApplyIdFromData(data) != applyId) { + if (data == null || !_isCpInvitePayload(data)) { continue; } final state = _cpInviteStateFromData(data); - if (state != _CpInviteMessageState.pending) { - return state; + final itemApplyId = _cpApplyIdFromData(data); + if (itemApplyId == applyId) { + if (state != _CpInviteMessageState.pending) { + return state; + } + continue; + } + if (state == _CpInviteMessageState.accepted && + _isSameCpInvitePair(currentData, data)) { + hasAcceptedSiblingInvite = true; } } + if (hasAcceptedSiblingInvite) { + return _CpInviteMessageState.rejected; + } return _CpInviteMessageState.pending; } + bool _isSameCpInvitePair( + Map left, + Map right, + ) { + final leftInviterIds = _cpInviteInviterIdentityValues(left); + final leftReceiverIds = _cpInviteReceiverIdentityValues(left); + final rightInviterIds = _cpInviteInviterIdentityValues(right); + final rightReceiverIds = _cpInviteReceiverIdentityValues(right); + if (leftInviterIds.isEmpty || + leftReceiverIds.isEmpty || + rightInviterIds.isEmpty || + rightReceiverIds.isEmpty) { + return false; + } + final sameDirection = + _hasAnyCommonCpIdentity(leftInviterIds, rightInviterIds) && + _hasAnyCommonCpIdentity(leftReceiverIds, rightReceiverIds); + final reversedDirection = + _hasAnyCommonCpIdentity(leftInviterIds, rightReceiverIds) && + _hasAnyCommonCpIdentity(leftReceiverIds, rightInviterIds); + return sameDirection || reversedDirection; + } + + bool _hasAnyCommonCpIdentity(Set left, Set right) { + if (left.isEmpty || right.isEmpty) { + return false; + } + return left.any(right.contains); + } + _CpInviteMessageState? _localCpInviteStateForData(Map data) { return _localCpInviteStateForApplyId(_cpApplyIdFromData(data)); } @@ -2168,7 +2230,10 @@ class _MessageItem extends StatelessWidget { if (!_isCpInvitePayload(data)) { return ""; } - final state = _cpInviteStateForMessage(data); + final state = _cpInviteStateFromData(data); + if (state == _CpInviteMessageState.pending) { + return ""; + } final applyId = _cpApplyIdFromData(data); if (applyId.isEmpty) { return ""; diff --git a/lib/ui_kit/widgets/room/cp/room_cp_invite_dialog.dart b/lib/ui_kit/widgets/room/cp/room_cp_invite_dialog.dart index c28a038..cb91f2c 100644 --- a/lib/ui_kit/widgets/room/cp/room_cp_invite_dialog.dart +++ b/lib/ui_kit/widgets/room/cp/room_cp_invite_dialog.dart @@ -41,6 +41,7 @@ class RoomCpInviteDialog extends StatefulWidget { this.titleText, this.descriptionText, this.bottomText, + this.statusText, this.acceptText = 'Accept', this.rejectText = 'Reject', this.onAccept, @@ -62,6 +63,7 @@ class RoomCpInviteDialog extends StatefulWidget { final String? titleText; final String? descriptionText; final String? bottomText; + final String? statusText; final String acceptText; final String rejectText; final VoidCallback? onAccept; @@ -82,6 +84,7 @@ class RoomCpInviteDialog extends StatefulWidget { String? titleText, String? descriptionText, String? bottomText, + String? statusText, String acceptText = 'Accept', String rejectText = 'Reject', VoidCallback? onAccept, @@ -108,6 +111,7 @@ class RoomCpInviteDialog extends StatefulWidget { titleText: titleText, descriptionText: descriptionText, bottomText: bottomText, + statusText: statusText, acceptText: acceptText, rejectText: rejectText, onAccept: onAccept, @@ -480,6 +484,10 @@ class _RoomCpInviteDialogState extends State { } String get _statusText { + final statusText = widget.statusText?.trim(); + if (statusText != null && statusText.isNotEmpty) { + return statusText; + } final localizations = SCAppLocalizations.of(context); switch (widget.actionState) { case RoomCpInviteActionState.expired: