修改消息和rtc
This commit is contained in:
parent
1e7261927e
commit
8f95b72fd0
@ -1224,6 +1224,11 @@ class _MessageItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
final customData = _customDataFromMessage(message);
|
||||||
|
if (customData != null &&
|
||||||
|
_isDuplicateCpResultMessageForConversation(customData)) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
final cpRelationFormedCard = _cpRelationFormedMessageCard();
|
final cpRelationFormedCard = _cpRelationFormedMessageCard();
|
||||||
final cpStatusLineText = _cpStatusLineTextForMessage();
|
final cpStatusLineText = _cpStatusLineTextForMessage();
|
||||||
return Container(
|
return Container(
|
||||||
@ -1381,7 +1386,7 @@ class _MessageItem extends StatelessWidget {
|
|||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onLongPress: () => _showMsgItemMenu(ct, ""),
|
onLongPress: () => _showMsgItemMenu(ct, ""),
|
||||||
onTap:
|
onTap:
|
||||||
() => _showCpInviteDialogFromMessage(data, cpInvite, actionState),
|
() => _openCpInviteDialogFromMessage(data, cpInvite, actionState),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 251.w,
|
width: 251.w,
|
||||||
height: 64.w,
|
height: 64.w,
|
||||||
@ -1451,6 +1456,30 @@ class _MessageItem extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _openCpInviteDialogFromMessage(
|
||||||
|
Map<String, dynamic> data,
|
||||||
|
SCSystemInvitMessageRes? cpInvite,
|
||||||
|
RoomCpInviteActionState actionState,
|
||||||
|
) {
|
||||||
|
unawaited(_openCpInviteDialogFromMessageAsync(data, cpInvite, actionState));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _openCpInviteDialogFromMessageAsync(
|
||||||
|
Map<String, dynamic> data,
|
||||||
|
SCSystemInvitMessageRes? cpInvite,
|
||||||
|
RoomCpInviteActionState actionState,
|
||||||
|
) async {
|
||||||
|
final latestState = await _latestCpInviteStateForMessage(data);
|
||||||
|
if (!context.mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final resolvedActionState =
|
||||||
|
latestState == _CpInviteMessageState.pending
|
||||||
|
? actionState
|
||||||
|
: _cpInviteActionState(latestState);
|
||||||
|
_showCpInviteDialogFromMessage(data, cpInvite, resolvedActionState);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildCpInviteGiftThumb(String giftCover) {
|
Widget _buildCpInviteGiftThumb(String giftCover) {
|
||||||
final child =
|
final child =
|
||||||
giftCover.isNotEmpty
|
giftCover.isNotEmpty
|
||||||
@ -1623,12 +1652,22 @@ class _MessageItem extends StatelessWidget {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final localizations = SCAppLocalizations.of(context)!;
|
final localizations = SCAppLocalizations.of(context)!;
|
||||||
|
final relationType = _cpRelationTypeFromMessageData(data);
|
||||||
if (state == _CpInviteMessageState.expired) {
|
if (state == _CpInviteMessageState.expired) {
|
||||||
|
if (relationType != "CP") {
|
||||||
|
return "The ${scCpRelationPossessiveLabel(relationType)} invitation timed out.";
|
||||||
|
}
|
||||||
return localizations.closeFriendInviteTimedOut;
|
return localizations.closeFriendInviteTimedOut;
|
||||||
}
|
}
|
||||||
|
if (relationType == "CP") {
|
||||||
|
return _isCurrentUserCpInviter(data)
|
||||||
|
? localizations.otherDeclinedCloseFriendInvite
|
||||||
|
: localizations.youDeclinedCloseFriendInvite;
|
||||||
|
}
|
||||||
|
final relationLabel = scCpRelationPossessiveLabel(relationType);
|
||||||
return _isCurrentUserCpInviter(data)
|
return _isCurrentUserCpInviter(data)
|
||||||
? localizations.otherDeclinedCloseFriendInvite
|
? "The other party declined your $relationLabel invitation."
|
||||||
: localizations.youDeclinedCloseFriendInvite;
|
: "You declined the other party's $relationLabel invitation.";
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showCpInviteDialogFromMessage(
|
void _showCpInviteDialogFromMessage(
|
||||||
@ -1782,14 +1821,15 @@ class _MessageItem extends StatelessWidget {
|
|||||||
cpInvite != null &&
|
cpInvite != null &&
|
||||||
actionState == RoomCpInviteActionState.pending &&
|
actionState == RoomCpInviteActionState.pending &&
|
||||||
applyId.isNotEmpty
|
applyId.isNotEmpty
|
||||||
? () => _processCpInviteFromMessage(applyId, cpInvite, true)
|
? () => _processCpInviteFromMessage(applyId, cpInvite, true, data)
|
||||||
: null,
|
: null,
|
||||||
onReject:
|
onReject:
|
||||||
!isInviter &&
|
!isInviter &&
|
||||||
cpInvite != null &&
|
cpInvite != null &&
|
||||||
actionState == RoomCpInviteActionState.pending &&
|
actionState == RoomCpInviteActionState.pending &&
|
||||||
applyId.isNotEmpty
|
applyId.isNotEmpty
|
||||||
? () => _processCpInviteFromMessage(applyId, cpInvite, false)
|
? () =>
|
||||||
|
_processCpInviteFromMessage(applyId, cpInvite, false, data)
|
||||||
: null,
|
: null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1798,16 +1838,37 @@ class _MessageItem extends StatelessWidget {
|
|||||||
String applyId,
|
String applyId,
|
||||||
SCSystemInvitMessageRes invite,
|
SCSystemInvitMessageRes invite,
|
||||||
bool agree,
|
bool agree,
|
||||||
|
Map<String, dynamic> data,
|
||||||
) {
|
) {
|
||||||
unawaited(_processCpInviteFromMessageAsync(applyId, invite, agree));
|
unawaited(_processCpInviteFromMessageAsync(applyId, invite, agree, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _processCpInviteFromMessageAsync(
|
Future<void> _processCpInviteFromMessageAsync(
|
||||||
String applyId,
|
String applyId,
|
||||||
SCSystemInvitMessageRes invite,
|
SCSystemInvitMessageRes invite,
|
||||||
bool agree,
|
bool agree,
|
||||||
|
Map<String, dynamic> data,
|
||||||
) async {
|
) async {
|
||||||
_cpMessageLog('process applyId=$applyId agree=$agree');
|
_cpMessageLog('process applyId=$applyId agree=$agree');
|
||||||
|
final latestState = await _latestCpInviteStateForMessage(data);
|
||||||
|
if (latestState != _CpInviteMessageState.pending) {
|
||||||
|
_cpMessageLog(
|
||||||
|
'skip process applyId=$applyId agree=$agree latestState=$latestState',
|
||||||
|
);
|
||||||
|
if (!context.mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_showCpInviteDialogFromMessage(
|
||||||
|
data,
|
||||||
|
invite,
|
||||||
|
_cpInviteActionState(latestState),
|
||||||
|
);
|
||||||
|
updateCall();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!context.mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
final profileManager = Provider.of<SocialChatUserProfileManager>(
|
final profileManager = Provider.of<SocialChatUserProfileManager>(
|
||||||
context,
|
context,
|
||||||
listen: false,
|
listen: false,
|
||||||
@ -1821,6 +1882,9 @@ class _MessageItem extends StatelessWidget {
|
|||||||
_cpMessageLog('process failed applyId=$applyId agree=$agree');
|
_cpMessageLog('process failed applyId=$applyId agree=$agree');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!context.mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
SmartDialog.dismiss(tag: RoomCpInviteDialog.dialogTag);
|
SmartDialog.dismiss(tag: RoomCpInviteDialog.dialogTag);
|
||||||
_cpMessageLog(
|
_cpMessageLog(
|
||||||
'process submitted applyId=$applyId agree=$agree '
|
'process submitted applyId=$applyId agree=$agree '
|
||||||
@ -1830,6 +1894,58 @@ class _MessageItem extends StatelessWidget {
|
|||||||
updateCall();
|
updateCall();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<_CpInviteMessageState> _latestCpInviteStateForMessage(
|
||||||
|
Map<String, dynamic> data,
|
||||||
|
) async {
|
||||||
|
final localState = _cpInviteStateForMessage(data);
|
||||||
|
if (localState != _CpInviteMessageState.pending) {
|
||||||
|
return localState;
|
||||||
|
}
|
||||||
|
final applyId = _cpApplyIdFromData(data);
|
||||||
|
if (applyId.isEmpty) {
|
||||||
|
return localState;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final status = await SCAccountRepository().cpRelationshipApplyStatus(
|
||||||
|
applyId,
|
||||||
|
);
|
||||||
|
final backendState = _cpInviteStateFromBackendStatus(status);
|
||||||
|
if (backendState != null) {
|
||||||
|
return backendState;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
_cpMessageLog('query apply status failed applyId=$applyId error=$error');
|
||||||
|
}
|
||||||
|
return _cpInviteSecondsLeft(data) <= 0
|
||||||
|
? _CpInviteMessageState.expired
|
||||||
|
: localState;
|
||||||
|
}
|
||||||
|
|
||||||
|
_CpInviteMessageState? _cpInviteStateFromBackendStatus(String? status) {
|
||||||
|
final text = status?.trim().toUpperCase() ?? "";
|
||||||
|
if (text.isEmpty || text == "WAIT" || text == "WAITING") {
|
||||||
|
return text.isEmpty ? null : _CpInviteMessageState.pending;
|
||||||
|
}
|
||||||
|
if (text.contains("EXPIRE") ||
|
||||||
|
text.contains("TIMEOUT") ||
|
||||||
|
text.contains("OVERDUE")) {
|
||||||
|
return _CpInviteMessageState.expired;
|
||||||
|
}
|
||||||
|
if (text.contains("REFUSE") ||
|
||||||
|
text.contains("REJECT") ||
|
||||||
|
text.contains("DECLIN") ||
|
||||||
|
text.contains("DENY")) {
|
||||||
|
return _CpInviteMessageState.rejected;
|
||||||
|
}
|
||||||
|
if (text.contains("AGREE") ||
|
||||||
|
text.contains("ACCEPT") ||
|
||||||
|
text.contains("APPROVE") ||
|
||||||
|
text.contains("ESTABLISH")) {
|
||||||
|
return _CpInviteMessageState.accepted;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, dynamic>? _customDataFromMessage(V2TimMessage msg) {
|
Map<String, dynamic>? _customDataFromMessage(V2TimMessage msg) {
|
||||||
if (msg.elemType != MessageElemType.V2TIM_ELEM_TYPE_CUSTOM) {
|
if (msg.elemType != MessageElemType.V2TIM_ELEM_TYPE_CUSTOM) {
|
||||||
return null;
|
return null;
|
||||||
@ -1891,6 +2007,60 @@ class _MessageItem extends StatelessWidget {
|
|||||||
return _CpInviteMessageState.pending;
|
return _CpInviteMessageState.pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _isDuplicateCpResultMessageForConversation(Map<String, dynamic> data) {
|
||||||
|
final currentKey = _cpResultMessageDedupKey(data);
|
||||||
|
if (currentKey.isEmpty) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final currentIndex = currentConversationMessageList.indexWhere(
|
||||||
|
_isCurrentConversationMessage,
|
||||||
|
);
|
||||||
|
if (currentIndex <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < currentIndex; i++) {
|
||||||
|
final otherData = _customDataFromMessage(
|
||||||
|
currentConversationMessageList[i],
|
||||||
|
);
|
||||||
|
if (otherData == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (_cpResultMessageDedupKey(otherData) == currentKey) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isCurrentConversationMessage(V2TimMessage item) {
|
||||||
|
final currentMsgId = message.msgID?.trim() ?? "";
|
||||||
|
final itemMsgId = item.msgID?.trim() ?? "";
|
||||||
|
if (currentMsgId.isNotEmpty && itemMsgId.isNotEmpty) {
|
||||||
|
return currentMsgId == itemMsgId;
|
||||||
|
}
|
||||||
|
final currentSeq = message.seq?.trim() ?? "";
|
||||||
|
final itemSeq = item.seq?.trim() ?? "";
|
||||||
|
if (currentSeq.isNotEmpty && itemSeq.isNotEmpty) {
|
||||||
|
return currentSeq == itemSeq && item.timestamp == message.timestamp;
|
||||||
|
}
|
||||||
|
return identical(item, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _cpResultMessageDedupKey(Map<String, dynamic> data) {
|
||||||
|
if (!_isCpInvitePayload(data)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
final state = _cpInviteStateFromData(data);
|
||||||
|
if (state == _CpInviteMessageState.pending) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
final applyId = _cpApplyIdFromData(data);
|
||||||
|
if (applyId.isEmpty) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return "$applyId|${state.name}";
|
||||||
|
}
|
||||||
|
|
||||||
_CpInviteMessageState _cpInviteStateFromData(Map<String, dynamic> data) {
|
_CpInviteMessageState _cpInviteStateFromData(Map<String, dynamic> data) {
|
||||||
final content = _cpContentMap(data);
|
final content = _cpContentMap(data);
|
||||||
final values = <String>[
|
final values = <String>[
|
||||||
@ -2145,6 +2315,20 @@ class _MessageItem extends StatelessWidget {
|
|||||||
], fallback: "");
|
], fallback: "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _cpRelationTypeFromMessageData(Map<String, dynamic> data) {
|
||||||
|
final invite = _cpInviteFromMessageData(data);
|
||||||
|
final content = _cpContentMap(data);
|
||||||
|
return scNormalizeCpRelationType(
|
||||||
|
_firstNonBlankString([
|
||||||
|
invite?.relationType,
|
||||||
|
data["relationType"]?.toString(),
|
||||||
|
data["relation_type"]?.toString(),
|
||||||
|
content["relationType"]?.toString(),
|
||||||
|
content["relation_type"]?.toString(),
|
||||||
|
], fallback: "CP"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, dynamic> _cpContentMap(Map<String, dynamic> data) {
|
Map<String, dynamic> _cpContentMap(Map<String, dynamic> data) {
|
||||||
final content = data["content"];
|
final content = data["content"];
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -458,7 +458,7 @@ class _MessageItem extends StatelessWidget {
|
|||||||
showMsgItemMenu(ct, "");
|
showMsgItemMenu(ct, "");
|
||||||
},
|
},
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_showCpInviteDialogFromMessage(data, cpInvite, actionState);
|
_openCpInviteDialogFromMessage(data, cpInvite, actionState);
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 251.w,
|
width: 251.w,
|
||||||
@ -529,6 +529,30 @@ class _MessageItem extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _openCpInviteDialogFromMessage(
|
||||||
|
Map<String, dynamic> data,
|
||||||
|
SCSystemInvitMessageRes? cpInvite,
|
||||||
|
RoomCpInviteActionState actionState,
|
||||||
|
) {
|
||||||
|
unawaited(_openCpInviteDialogFromMessageAsync(data, cpInvite, actionState));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _openCpInviteDialogFromMessageAsync(
|
||||||
|
Map<String, dynamic> data,
|
||||||
|
SCSystemInvitMessageRes? cpInvite,
|
||||||
|
RoomCpInviteActionState actionState,
|
||||||
|
) async {
|
||||||
|
final latestState = await _latestCpInviteStateForMessage(data);
|
||||||
|
if (!context.mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final resolvedActionState =
|
||||||
|
latestState == _CpInviteMessageState.pending
|
||||||
|
? actionState
|
||||||
|
: _cpInviteActionState(latestState);
|
||||||
|
_showCpInviteDialogFromMessage(data, cpInvite, resolvedActionState);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildCpInviteGiftThumb(String giftCover) {
|
Widget _buildCpInviteGiftThumb(String giftCover) {
|
||||||
final child =
|
final child =
|
||||||
giftCover.isNotEmpty
|
giftCover.isNotEmpty
|
||||||
@ -788,6 +812,7 @@ class _MessageItem extends StatelessWidget {
|
|||||||
applyId,
|
applyId,
|
||||||
SCSysytemMessageType.CP_BUILD.name,
|
SCSysytemMessageType.CP_BUILD.name,
|
||||||
cpInvite: cpInvite,
|
cpInvite: cpInvite,
|
||||||
|
cpData: data,
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
onReject:
|
onReject:
|
||||||
@ -798,6 +823,7 @@ class _MessageItem extends StatelessWidget {
|
|||||||
applyId,
|
applyId,
|
||||||
SCSysytemMessageType.CP_BUILD.name,
|
SCSysytemMessageType.CP_BUILD.name,
|
||||||
cpInvite: cpInvite,
|
cpInvite: cpInvite,
|
||||||
|
cpData: data,
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
);
|
);
|
||||||
@ -856,6 +882,56 @@ class _MessageItem extends StatelessWidget {
|
|||||||
: _CpInviteMessageState.pending;
|
: _CpInviteMessageState.pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<_CpInviteMessageState> _latestCpInviteStateForMessage(
|
||||||
|
Map<String, dynamic> data,
|
||||||
|
) async {
|
||||||
|
final localState = _cpInviteStateForMessage(data);
|
||||||
|
if (localState != _CpInviteMessageState.pending) {
|
||||||
|
return localState;
|
||||||
|
}
|
||||||
|
final applyId = _cpApplyIdFromData(data);
|
||||||
|
if (applyId.isEmpty) {
|
||||||
|
return localState;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final status = await SCAccountRepository().cpRelationshipApplyStatus(
|
||||||
|
applyId,
|
||||||
|
);
|
||||||
|
final backendState = _cpInviteStateFromBackendStatus(status);
|
||||||
|
if (backendState != null) {
|
||||||
|
return backendState;
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
return _cpInviteSecondsLeft(data) <= 0
|
||||||
|
? _CpInviteMessageState.expired
|
||||||
|
: localState;
|
||||||
|
}
|
||||||
|
|
||||||
|
_CpInviteMessageState? _cpInviteStateFromBackendStatus(String? status) {
|
||||||
|
final text = status?.trim().toUpperCase() ?? "";
|
||||||
|
if (text.isEmpty || text == "WAIT" || text == "WAITING") {
|
||||||
|
return text.isEmpty ? null : _CpInviteMessageState.pending;
|
||||||
|
}
|
||||||
|
if (text.contains("EXPIRE") ||
|
||||||
|
text.contains("TIMEOUT") ||
|
||||||
|
text.contains("OVERDUE")) {
|
||||||
|
return _CpInviteMessageState.expired;
|
||||||
|
}
|
||||||
|
if (text.contains("REFUSE") ||
|
||||||
|
text.contains("REJECT") ||
|
||||||
|
text.contains("DECLIN") ||
|
||||||
|
text.contains("DENY")) {
|
||||||
|
return _CpInviteMessageState.rejected;
|
||||||
|
}
|
||||||
|
if (text.contains("AGREE") ||
|
||||||
|
text.contains("ACCEPT") ||
|
||||||
|
text.contains("APPROVE") ||
|
||||||
|
text.contains("ESTABLISH")) {
|
||||||
|
return _CpInviteMessageState.accepted;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
_CpInviteMessageState _cpInviteStateFromConversation(
|
_CpInviteMessageState _cpInviteStateFromConversation(
|
||||||
Map<String, dynamic> currentData,
|
Map<String, dynamic> currentData,
|
||||||
) {
|
) {
|
||||||
@ -1863,7 +1939,14 @@ class _MessageItem extends StatelessWidget {
|
|||||||
Future<void> _acceptCpInviteDirect(
|
Future<void> _acceptCpInviteDirect(
|
||||||
String id,
|
String id,
|
||||||
SCSystemInvitMessageRes? cpInvite,
|
SCSystemInvitMessageRes? cpInvite,
|
||||||
|
Map<String, dynamic>? cpData,
|
||||||
) async {
|
) async {
|
||||||
|
if (!await _shouldProcessCpInvite(id, cpInvite, cpData)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!context.mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
final profileManager = Provider.of<SocialChatUserProfileManager>(
|
final profileManager = Provider.of<SocialChatUserProfileManager>(
|
||||||
context,
|
context,
|
||||||
listen: false,
|
listen: false,
|
||||||
@ -1882,7 +1965,14 @@ class _MessageItem extends StatelessWidget {
|
|||||||
Future<void> _rejectCpInviteDirect(
|
Future<void> _rejectCpInviteDirect(
|
||||||
String id,
|
String id,
|
||||||
SCSystemInvitMessageRes? cpInvite,
|
SCSystemInvitMessageRes? cpInvite,
|
||||||
|
Map<String, dynamic>? cpData,
|
||||||
) async {
|
) async {
|
||||||
|
if (!await _shouldProcessCpInvite(id, cpInvite, cpData)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!context.mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
final profileManager = Provider.of<SocialChatUserProfileManager>(
|
final profileManager = Provider.of<SocialChatUserProfileManager>(
|
||||||
context,
|
context,
|
||||||
listen: false,
|
listen: false,
|
||||||
@ -1898,9 +1988,62 @@ class _MessageItem extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void acceptOpt(String id, String type, {SCSystemInvitMessageRes? cpInvite}) {
|
Future<bool> _shouldProcessCpInvite(
|
||||||
|
String applyId,
|
||||||
|
SCSystemInvitMessageRes? cpInvite,
|
||||||
|
Map<String, dynamic>? data,
|
||||||
|
) async {
|
||||||
|
final latestState =
|
||||||
|
data == null
|
||||||
|
? await _latestCpInviteStateForApplyId(applyId)
|
||||||
|
: await _latestCpInviteStateForMessage(data);
|
||||||
|
if (latestState == _CpInviteMessageState.pending) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!context.mounted) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (data != null) {
|
||||||
|
_showCpInviteDialogFromMessage(
|
||||||
|
data,
|
||||||
|
cpInvite,
|
||||||
|
_cpInviteActionState(latestState),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
SmartDialog.dismiss(tag: RoomCpInviteDialog.dialogTag);
|
||||||
|
if (latestState == _CpInviteMessageState.expired) {
|
||||||
|
SCTts.show(SCAppLocalizations.of(context)!.closeFriendInviteTimedOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateCall();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<_CpInviteMessageState> _latestCpInviteStateForApplyId(
|
||||||
|
String applyId,
|
||||||
|
) async {
|
||||||
|
if (applyId.trim().isEmpty) {
|
||||||
|
return _CpInviteMessageState.pending;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final status = await SCAccountRepository().cpRelationshipApplyStatus(
|
||||||
|
applyId,
|
||||||
|
);
|
||||||
|
return _cpInviteStateFromBackendStatus(status) ??
|
||||||
|
_CpInviteMessageState.pending;
|
||||||
|
} catch (_) {
|
||||||
|
return _CpInviteMessageState.pending;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void acceptOpt(
|
||||||
|
String id,
|
||||||
|
String type, {
|
||||||
|
SCSystemInvitMessageRes? cpInvite,
|
||||||
|
Map<String, dynamic>? cpData,
|
||||||
|
}) {
|
||||||
if (type == SCSysytemMessageType.CP_BUILD.name) {
|
if (type == SCSysytemMessageType.CP_BUILD.name) {
|
||||||
unawaited(_acceptCpInviteDirect(id, cpInvite));
|
unawaited(_acceptCpInviteDirect(id, cpInvite, cpData));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SmartDialog.show(
|
SmartDialog.show(
|
||||||
@ -1948,9 +2091,14 @@ class _MessageItem extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rejectOpt(String id, String type, {SCSystemInvitMessageRes? cpInvite}) {
|
void rejectOpt(
|
||||||
|
String id,
|
||||||
|
String type, {
|
||||||
|
SCSystemInvitMessageRes? cpInvite,
|
||||||
|
Map<String, dynamic>? cpData,
|
||||||
|
}) {
|
||||||
if (type == SCSysytemMessageType.CP_BUILD.name) {
|
if (type == SCSysytemMessageType.CP_BUILD.name) {
|
||||||
unawaited(_rejectCpInviteDirect(id, cpInvite));
|
unawaited(_rejectCpInviteDirect(id, cpInvite, cpData));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SmartDialog.show(
|
SmartDialog.show(
|
||||||
|
|||||||
@ -434,8 +434,10 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
.addConversationListener(
|
.addConversationListener(
|
||||||
listener: V2TimConversationListener(
|
listener: V2TimConversationListener(
|
||||||
onNewConversation: (conversationList) {
|
onNewConversation: (conversationList) {
|
||||||
// _onRefreshConversation(conversationList);
|
_onRefreshConversation(conversationList);
|
||||||
initConversation();
|
},
|
||||||
|
onConversationChanged: (conversationList) {
|
||||||
|
_onRefreshConversation(conversationList);
|
||||||
},
|
},
|
||||||
onTotalUnreadMessageCountChanged: (int totalUnreadCount) {
|
onTotalUnreadMessageCountChanged: (int totalUnreadCount) {
|
||||||
messageUnReadCount = totalUnreadCount;
|
messageUnReadCount = totalUnreadCount;
|
||||||
@ -605,7 +607,11 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
conversationMap.clear();
|
conversationMap.clear();
|
||||||
if (conversationList != null) {
|
if (conversationList != null) {
|
||||||
for (V2TimConversation? conversation in conversationList) {
|
for (V2TimConversation? conversation in conversationList) {
|
||||||
conversationMap[conversation!.conversationID] = conversation;
|
if (conversation == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
conversationMap[conversation.conversationID] = conversation;
|
||||||
|
_handleCpBuildFromConversation(conversation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getConversationList();
|
getConversationList();
|
||||||
@ -853,6 +859,13 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
if (data == null) {
|
if (data == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
final relationNoticePeerId = _cpRelationNoticePeerIdFromData(
|
||||||
|
data,
|
||||||
|
message: message,
|
||||||
|
);
|
||||||
|
if (relationNoticePeerId != null) {
|
||||||
|
return relationNoticePeerId;
|
||||||
|
}
|
||||||
final invite = _cpInviteFromMessageData(data);
|
final invite = _cpInviteFromMessageData(data);
|
||||||
final currentProfile = AccountStorage().getCurrentUser()?.userProfile;
|
final currentProfile = AccountStorage().getCurrentUser()?.userProfile;
|
||||||
if (invite == null || currentProfile == null) {
|
if (invite == null || currentProfile == null) {
|
||||||
@ -930,6 +943,9 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
if (_handleCpInviteResultMessage(data, msgId: message?.msgID)) {
|
if (_handleCpInviteResultMessage(data, msgId: message?.msgID)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (_handleCpRelationRefreshNoticeMessage(data, message: message)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (noticeType != SCSysytemMessageType.CP_BUILD.name) {
|
if (noticeType != SCSysytemMessageType.CP_BUILD.name) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1241,6 +1257,47 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _handleCpRelationRefreshNoticeMessage(
|
||||||
|
Map<String, dynamic> data, {
|
||||||
|
V2TimMessage? message,
|
||||||
|
}) {
|
||||||
|
final noticeType = _cpRelationNoticeTypeFromData(data);
|
||||||
|
if (!_isCpRelationRefreshNoticeType(noticeType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_cpInviteLog(
|
||||||
|
'handle CP relation refresh notice noticeType=$noticeType raw=$data',
|
||||||
|
);
|
||||||
|
final context = navigatorKey.currentState?.context;
|
||||||
|
if (context != null) {
|
||||||
|
unawaited(
|
||||||
|
Provider.of<SocialChatUserProfileManager>(
|
||||||
|
context,
|
||||||
|
listen: false,
|
||||||
|
).refreshLoadedCpProfiles(),
|
||||||
|
);
|
||||||
|
if (noticeType == SCSysytemMessageType.CP_DISMISS.name) {
|
||||||
|
final currentUserId =
|
||||||
|
AccountStorage().getCurrentUser()?.userProfile?.id?.trim() ?? "";
|
||||||
|
final peerUserId = _cpRelationNoticePeerIdFromData(
|
||||||
|
data,
|
||||||
|
message: message,
|
||||||
|
);
|
||||||
|
if (currentUserId.isNotEmpty && peerUserId != null) {
|
||||||
|
Provider.of<RtcProvider?>(
|
||||||
|
context,
|
||||||
|
listen: false,
|
||||||
|
)?.invalidateRoomMicRelationBetween(
|
||||||
|
userId: currentUserId,
|
||||||
|
peerUserId: peerUserId,
|
||||||
|
relationType: _cpRelationTypeFromNoticeData(data),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _showCpInviteResultDialog({
|
Future<void> _showCpInviteResultDialog({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required Map<String, dynamic> data,
|
required Map<String, dynamic> data,
|
||||||
@ -2039,13 +2096,88 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
content["type"]?.toString(),
|
content["type"]?.toString(),
|
||||||
])?.toUpperCase() ??
|
])?.toUpperCase() ??
|
||||||
"";
|
"";
|
||||||
if (noticeType == SCSysytemMessageType.CP_BUILD.name) {
|
if (noticeType == SCSysytemMessageType.CP_BUILD.name ||
|
||||||
|
_isCpRelationRefreshNoticeType(noticeType)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return _cpInviteApplyIdFromData(data).isNotEmpty &&
|
return _cpInviteApplyIdFromData(data).isNotEmpty &&
|
||||||
_cpInviteResultFromMessageData(data) != null;
|
_cpInviteResultFromMessageData(data) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _cpRelationNoticeTypeFromData(Map<String, dynamic> data) {
|
||||||
|
final content = _cpInviteContentMap(data);
|
||||||
|
return (_firstCpInviteValue([
|
||||||
|
data["noticeType"]?.toString(),
|
||||||
|
data["type"]?.toString(),
|
||||||
|
content["noticeType"]?.toString(),
|
||||||
|
content["type"]?.toString(),
|
||||||
|
]) ??
|
||||||
|
"")
|
||||||
|
.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isCpRelationRefreshNoticeType(String noticeType) {
|
||||||
|
return noticeType == SCSysytemMessageType.CP_DISMISS.name ||
|
||||||
|
noticeType == SCSysytemMessageType.CP_BLESS.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
String _cpRelationTypeFromNoticeData(Map<String, dynamic> data) {
|
||||||
|
final content = _cpInviteContentMap(data);
|
||||||
|
return scNormalizeCpRelationType(
|
||||||
|
_firstCpInviteValue([
|
||||||
|
data["relationType"]?.toString(),
|
||||||
|
data["relation_type"]?.toString(),
|
||||||
|
content["relationType"]?.toString(),
|
||||||
|
content["relation_type"]?.toString(),
|
||||||
|
]) ??
|
||||||
|
"CP",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String? _cpRelationNoticePeerIdFromData(
|
||||||
|
Map<String, dynamic> data, {
|
||||||
|
V2TimMessage? message,
|
||||||
|
}) {
|
||||||
|
if (!_isCpRelationRefreshNoticeType(_cpRelationNoticeTypeFromData(data))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final content = _cpInviteContentMap(data);
|
||||||
|
final currentProfile = AccountStorage().getCurrentUser()?.userProfile;
|
||||||
|
final currentIds =
|
||||||
|
[currentProfile?.id, currentProfile?.account]
|
||||||
|
.map((value) => value?.trim() ?? "")
|
||||||
|
.where((value) => value.isNotEmpty)
|
||||||
|
.toSet();
|
||||||
|
final candidates = <String?>[
|
||||||
|
data["expand"]?.toString(),
|
||||||
|
content["expand"]?.toString(),
|
||||||
|
data["peerUserId"]?.toString(),
|
||||||
|
data["cpUserId"]?.toString(),
|
||||||
|
data["targetUserId"]?.toString(),
|
||||||
|
data["senderUserId"]?.toString(),
|
||||||
|
data["fromUserId"]?.toString(),
|
||||||
|
data["userId"]?.toString(),
|
||||||
|
content["peerUserId"]?.toString(),
|
||||||
|
content["cpUserId"]?.toString(),
|
||||||
|
content["targetUserId"]?.toString(),
|
||||||
|
content["senderUserId"]?.toString(),
|
||||||
|
content["fromUserId"]?.toString(),
|
||||||
|
content["userId"]?.toString(),
|
||||||
|
message?.sender,
|
||||||
|
message?.userID,
|
||||||
|
];
|
||||||
|
for (final candidate in candidates) {
|
||||||
|
final userId = candidate?.trim() ?? "";
|
||||||
|
if (userId.isEmpty ||
|
||||||
|
currentIds.contains(userId) ||
|
||||||
|
!scLooksLikeBackendUserId(userId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
void _cpInviteLog(String message) {
|
void _cpInviteLog(String message) {
|
||||||
debugPrint('[CP][Invite] $message');
|
debugPrint('[CP][Invite] $message');
|
||||||
}
|
}
|
||||||
@ -2053,10 +2185,23 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
|||||||
void _onRefreshConversation(List<V2TimConversation> conversations) {
|
void _onRefreshConversation(List<V2TimConversation> conversations) {
|
||||||
for (V2TimConversation conversation in conversations) {
|
for (V2TimConversation conversation in conversations) {
|
||||||
conversationMap[conversation.conversationID] = conversation;
|
conversationMap[conversation.conversationID] = conversation;
|
||||||
|
_handleCpBuildFromConversation(conversation);
|
||||||
}
|
}
|
||||||
getConversationList();
|
getConversationList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _handleCpBuildFromConversation(V2TimConversation conversation) {
|
||||||
|
final message = conversation.lastMessage;
|
||||||
|
if (message == null || message.groupID != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final data = _decodeCpSystemMessageData(message);
|
||||||
|
if (!_isCpRelationInviteNoticeData(data)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unawaited(_handleIncomingCpBuildMessage(message));
|
||||||
|
}
|
||||||
|
|
||||||
///创建房间im群聊
|
///创建房间im群聊
|
||||||
Future<V2TimValueCallback<String>> createRoomGroup(
|
Future<V2TimValueCallback<String>> createRoomGroup(
|
||||||
String groupID,
|
String groupID,
|
||||||
|
|||||||
@ -178,22 +178,28 @@ class SocialChatUserProfileManager extends ChangeNotifier {
|
|||||||
if (userId.trim().isEmpty) {
|
if (userId.trim().isEmpty) {
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
final cpPairs = <CPRes>[];
|
final fallbackCpPairs = <CPRes>[];
|
||||||
final closeFriendPairs = <CPRes>[];
|
final fallbackCloseFriendPairs = <CPRes>[];
|
||||||
_addCpRelationPairs(
|
_addCpRelationPairs(
|
||||||
cpPairs: cpPairs,
|
cpPairs: fallbackCpPairs,
|
||||||
closeFriendPairs: closeFriendPairs,
|
closeFriendPairs: fallbackCloseFriendPairs,
|
||||||
relations: profile.cpList,
|
relations: profile.cpList,
|
||||||
fallbackRelationType: 'CP',
|
fallbackRelationType: 'CP',
|
||||||
);
|
);
|
||||||
_addCpRelationPairs(
|
_addCpRelationPairs(
|
||||||
cpPairs: cpPairs,
|
cpPairs: fallbackCpPairs,
|
||||||
closeFriendPairs: closeFriendPairs,
|
closeFriendPairs: fallbackCloseFriendPairs,
|
||||||
relations: profile.closeFriendList,
|
relations: profile.closeFriendList,
|
||||||
);
|
);
|
||||||
|
final cpPairs = <CPRes>[];
|
||||||
|
final closeFriendPairs = <CPRes>[];
|
||||||
|
var loadedAnyCabin = false;
|
||||||
await Future.wait(
|
await Future.wait(
|
||||||
_cpProfileRelationTypes.map((relationType) async {
|
_cpProfileRelationTypes.map((relationType) async {
|
||||||
final cabin = await _safeLoadCpCabin(userId, relationType);
|
final cabin = await _safeLoadCpCabin(userId, relationType);
|
||||||
|
if (cabin != null) {
|
||||||
|
loadedAnyCabin = true;
|
||||||
|
}
|
||||||
final cpPair = cabin?.cpPairUserProfileCO;
|
final cpPair = cabin?.cpPairUserProfileCO;
|
||||||
if (cpPair == null || !_hasCpPair(cpPair)) {
|
if (cpPair == null || !_hasCpPair(cpPair)) {
|
||||||
return;
|
return;
|
||||||
@ -231,6 +237,12 @@ class SocialChatUserProfileManager extends ChangeNotifier {
|
|||||||
'closeFriends=${closeFriendPairs.length}',
|
'closeFriends=${closeFriendPairs.length}',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (!loadedAnyCabin) {
|
||||||
|
return profile.copyWith(
|
||||||
|
cpList: fallbackCpPairs,
|
||||||
|
closeFriendList: fallbackCloseFriendPairs,
|
||||||
|
);
|
||||||
|
}
|
||||||
return profile.copyWith(
|
return profile.copyWith(
|
||||||
cpList: cpPairs,
|
cpList: cpPairs,
|
||||||
closeFriendList: closeFriendPairs,
|
closeFriendList: closeFriendPairs,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user