2149 lines
77 KiB
Dart
2149 lines
77 KiB
Dart
import 'dart:async';
|
||
import 'dart:convert';
|
||
import 'package:extended_image/extended_image.dart'
|
||
show ExtendedImage, ExtendedRawImage, ExtendedImageState, LoadState;
|
||
import 'package:extended_text/extended_text.dart';
|
||
import 'package:flutter/cupertino.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter/services.dart';
|
||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||
import 'package:yumi/ui_kit/components/sc_compontent.dart';
|
||
import 'package:yumi/ui_kit/components/text/sc_text.dart';
|
||
import 'package:yumi/app/routes/sc_fluro_navigator.dart';
|
||
import 'package:yumi/shared/tools/sc_system_message_utils.dart';
|
||
import 'package:yumi/shared/data_sources/sources/repositories/sc_user_repository_impl.dart';
|
||
import 'package:provider/provider.dart';
|
||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||
import 'package:tencent_cloud_chat_sdk/enum/message_elem_type.dart';
|
||
import 'package:tencent_cloud_chat_sdk/enum/message_status.dart';
|
||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_callback.dart';
|
||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart';
|
||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_custom_elem.dart';
|
||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart';
|
||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_text_elem.dart';
|
||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_value_callback.dart';
|
||
import 'package:tencent_cloud_chat_sdk/tencent_im_sdk_plugin.dart';
|
||
|
||
import 'package:yumi/app_localizations.dart';
|
||
import 'package:yumi/ui_kit/components/appbar/socialchat_appbar.dart';
|
||
import 'package:yumi/ui_kit/components/dialog/dialog_base.dart';
|
||
import 'package:yumi/ui_kit/components/sc_tts.dart';
|
||
import 'package:yumi/ui_kit/theme/socialchat_theme.dart';
|
||
import 'package:yumi/app/constants/sc_screen.dart';
|
||
import 'package:yumi/shared/tools/sc_date_utils.dart';
|
||
import 'package:yumi/shared/tools/sc_cp_relation_notice_utils.dart';
|
||
import 'package:yumi/services/general/sc_app_general_manager.dart';
|
||
import 'package:yumi/services/audio/rtm_manager.dart';
|
||
import 'package:yumi/services/auth/user_profile_manager.dart';
|
||
import 'package:yumi/shared/data_sources/sources/local/user_manager.dart';
|
||
import 'package:yumi/modules/store/store_route.dart';
|
||
import 'package:yumi/app/constants/sc_global_config.dart';
|
||
import 'package:yumi/app/config/business_logic_strategy.dart';
|
||
import 'package:yumi/ui_kit/widgets/room/cp/room_cp_relation_formed_dialog.dart';
|
||
import 'package:yumi/ui_kit/widgets/room/cp/room_cp_invite_dialog.dart';
|
||
|
||
import '../../../shared/data_sources/models/enum/sc_sysytem_message_type.dart';
|
||
import '../../../shared/business_logic/models/res/sc_system_invit_message_res.dart';
|
||
|
||
enum _CpInviteMessageState { pending, expired, rejected, accepted }
|
||
|
||
class MessageSystemPage extends StatefulWidget {
|
||
final V2TimConversation? conversation;
|
||
final bool shrinkWrap;
|
||
|
||
//是否是房间内聊天界面。
|
||
final bool inRoom;
|
||
|
||
const MessageSystemPage({
|
||
Key? key,
|
||
this.conversation,
|
||
this.shrinkWrap = false,
|
||
this.inRoom = false,
|
||
}) : super(key: key);
|
||
|
||
@override
|
||
_MessageSystemPageState createState() => _MessageSystemPageState();
|
||
}
|
||
|
||
class _MessageSystemPageState extends State<MessageSystemPage> {
|
||
final ScrollController _scrollController = ScrollController();
|
||
final RefreshController _refreshController = RefreshController();
|
||
RtmProvider? rtmProvider;
|
||
V2TimConversation? currentConversation;
|
||
List<V2TimMessage> currentConversationMessageList = [];
|
||
|
||
BusinessLogicStrategy get _strategy => SCGlobalConfig.businessLogicStrategy;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
rtmProvider = Provider.of<RtmProvider>(context, listen: false);
|
||
currentConversation = widget.conversation;
|
||
rtmProvider?.onNewMessageCurrentConversationListener = _onNewMessage;
|
||
loadMsg();
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
rtmProvider?.onNewMessageCurrentConversationListener = null;
|
||
super.dispose();
|
||
}
|
||
|
||
Future<void> loadMsg() async {
|
||
V2TimValueCallback<List<V2TimMessage>> v2timValueCallback =
|
||
await TencentImSDKPlugin.v2TIMManager
|
||
.getMessageManager()
|
||
.getC2CHistoryMessageList(
|
||
userID: currentConversation!.userID!,
|
||
count: 100,
|
||
lastMsgID: null,
|
||
);
|
||
List<V2TimMessage> messages = v2timValueCallback.data ?? [];
|
||
// List<V2TimMessage> messages = await FTIM.getMessageManager().getMessages(conversation: currentConversation);
|
||
currentConversationMessageList ??= [];
|
||
currentConversationMessageList?.clear();
|
||
|
||
for (var msg in messages) {
|
||
if (!msg.isSelf! && msg.isPeerRead!) {
|
||
TencentImSDKPlugin.v2TIMManager
|
||
.getMessageManager()
|
||
.sendMessageReadReceipts(messageIDList: [msg.msgID!]);
|
||
}
|
||
}
|
||
currentConversationMessageList.insertAll(0, messages);
|
||
setState(() {});
|
||
_scrollController.jumpTo(0.0);
|
||
}
|
||
|
||
_onNewMessage(V2TimMessage? message, {String? msgId}) async {
|
||
if (message == null) {
|
||
return;
|
||
}
|
||
if (message.userID != currentConversation?.userID) return;
|
||
int? index;
|
||
for (var element in currentConversationMessageList) {
|
||
if (msgId != null) {
|
||
if (msgId == element.msgID) {
|
||
element.status = MessageStatus.V2TIM_MSG_STATUS_SEND_FAIL;
|
||
setState(() {});
|
||
continue;
|
||
}
|
||
} else {
|
||
if (element.msgID == message.msgID) {
|
||
index = currentConversationMessageList.indexOf(element);
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
if (msgId != null) {
|
||
return;
|
||
}
|
||
if (index != null) {
|
||
currentConversationMessageList.removeAt(index!);
|
||
currentConversationMessageList.insert(index!, message);
|
||
} else {
|
||
currentConversationMessageList.insert(0, message);
|
||
}
|
||
_refreshCpStateForMessage(message);
|
||
await TencentImSDKPlugin.v2TIMManager
|
||
.getMessageManager()
|
||
.markC2CMessageAsRead(userID: currentConversation!.userID!);
|
||
//发送已读回执
|
||
await TencentImSDKPlugin.v2TIMManager
|
||
.getMessageManager()
|
||
.sendMessageReadReceipts(messageIDList: [message.msgID!]);
|
||
setState(() {});
|
||
// await FTIM.getContactManager().setReadMessage(currentConversation);
|
||
}
|
||
|
||
void _refreshCpStateForMessage(V2TimMessage message) {
|
||
if (message.elemType != MessageElemType.V2TIM_ELEM_TYPE_CUSTOM) {
|
||
return;
|
||
}
|
||
final content = message.customElem?.data;
|
||
if (content == null || content.isEmpty) {
|
||
return;
|
||
}
|
||
try {
|
||
final data = jsonDecode(content);
|
||
final noticeType = data["noticeType"]?.toString();
|
||
if (noticeType == SCSysytemMessageType.CP_DISMISS.name ||
|
||
noticeType == SCSysytemMessageType.CP_BLESS.name) {
|
||
Provider.of<SocialChatUserProfileManager>(
|
||
context,
|
||
listen: false,
|
||
).refreshLoadedCpProfiles();
|
||
}
|
||
} catch (_) {}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Stack(
|
||
children: [
|
||
Image.asset(
|
||
_strategy.getSCMessageChatPageRoomSettingBackground(),
|
||
width: ScreenUtil().screenWidth,
|
||
height: ScreenUtil().screenHeight,
|
||
fit: BoxFit.fill,
|
||
),
|
||
Scaffold(
|
||
backgroundColor: Colors.transparent,
|
||
resizeToAvoidBottomInset: false,
|
||
appBar: SocialChatStandardAppBar(
|
||
title: SCAppLocalizations.of(context)!.system,
|
||
actions: [],
|
||
),
|
||
body: SafeArea(top: false, child: _msgList()),
|
||
),
|
||
],
|
||
);
|
||
}
|
||
|
||
Widget _msgList() {
|
||
return SmartRefresher(
|
||
enablePullDown: false,
|
||
enablePullUp: true,
|
||
onLoading: () async {
|
||
if (currentConversationMessageList.isNotEmpty) {
|
||
// 拉取单聊历史消息
|
||
// 首次拉取,lastMsgID 设置为 null
|
||
// 再次拉取时,lastMsgID 可以使用返回的消息列表中的最后一条消息的id
|
||
V2TimValueCallback<List<V2TimMessage>> v2timValueCallback =
|
||
await TencentImSDKPlugin.v2TIMManager
|
||
.getMessageManager()
|
||
.getC2CHistoryMessageList(
|
||
userID: currentConversation!.userID ?? "",
|
||
count: 30,
|
||
lastMsgID: currentConversationMessageList.last.msgID,
|
||
);
|
||
List<V2TimMessage> messages =
|
||
v2timValueCallback.data as List<V2TimMessage>;
|
||
currentConversationMessageList.addAll(messages);
|
||
if (messages.length == 30) {
|
||
_refreshController.loadComplete();
|
||
} else {
|
||
_refreshController.loadNoData();
|
||
}
|
||
} else {
|
||
_refreshController.loadNoData();
|
||
}
|
||
setState(() {});
|
||
},
|
||
footer: CustomFooter(
|
||
height: 1,
|
||
builder: (context, mode) {
|
||
return SizedBox(
|
||
height: 1,
|
||
width: 1,
|
||
child: SizedBox(height: 1, width: 1),
|
||
);
|
||
},
|
||
),
|
||
controller: _refreshController,
|
||
child: Container(
|
||
child: CustomScrollView(
|
||
shrinkWrap: currentConversationMessageList.length > 10 ? false : true,
|
||
controller: _scrollController,
|
||
reverse: true,
|
||
physics: const ClampingScrollPhysics(),
|
||
// 禁用回弹效果
|
||
slivers: [
|
||
SliverList(
|
||
delegate: SliverChildBuilderDelegate(
|
||
(c, i) => _MessageItem(
|
||
message: currentConversationMessageList[i],
|
||
preMessage:
|
||
i < currentConversationMessageList.length - 1
|
||
? currentConversationMessageList[i + 1]
|
||
: null,
|
||
currentConversationMessageList:
|
||
currentConversationMessageList,
|
||
updateCall: () {
|
||
setState(() {});
|
||
},
|
||
),
|
||
childCount: currentConversationMessageList.length,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
class _MessageItem extends StatelessWidget {
|
||
final V2TimMessage message;
|
||
final V2TimMessage? preMessage;
|
||
List<V2TimMessage> currentConversationMessageList = [];
|
||
Function updateCall;
|
||
|
||
///上一条
|
||
late BuildContext context;
|
||
|
||
_MessageItem({
|
||
required this.message,
|
||
this.preMessage,
|
||
required this.currentConversationMessageList,
|
||
required this.updateCall,
|
||
});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
this.context = context;
|
||
bool showTime = true;
|
||
int timestamp = (message.timestamp ?? 0) * 1000;
|
||
int preTimestamp = (preMessage?.timestamp ?? 0) * 1000;
|
||
if (preMessage != null) {
|
||
///5分钟以内 不显示
|
||
if (DateTime.fromMillisecondsSinceEpoch(timestamp)
|
||
.difference(DateTime.fromMillisecondsSinceEpoch(preTimestamp))
|
||
.inMilliseconds <
|
||
1000 * 60 * 5) {
|
||
showTime = false;
|
||
}
|
||
}
|
||
String time = SCMDateUtils.formatMessageTime(
|
||
context,
|
||
DateTime.fromMillisecondsSinceEpoch(timestamp ?? 0),
|
||
);
|
||
String noticeType = "";
|
||
String tagHead = "";
|
||
if (message.elemType == MessageElemType.V2TIM_ELEM_TYPE_CUSTOM) {
|
||
V2TimCustomElem customElem = message.customElem!;
|
||
String content = customElem.data ?? "";
|
||
try {
|
||
final data = jsonDecode(content);
|
||
noticeType = data["noticeType"]?.toString() ?? "";
|
||
if (noticeType == SCSysytemMessageType.CP_LOVE_LETTER.name ||
|
||
noticeType == SCSysytemMessageType.CP_DISMISS.name ||
|
||
noticeType == SCSysytemMessageType.CP_BLESS.name) {
|
||
var bean = SCSystemInvitMessageRes.fromJson(
|
||
jsonDecode(data["content"]),
|
||
);
|
||
tagHead = bean.userAvatar ?? "";
|
||
}
|
||
} catch (_) {}
|
||
}
|
||
final cpRelationFormedCard = _cpRelationFormedMessageCard();
|
||
final cpStatusLineText = _cpStatusLineTextForMessage();
|
||
return Container(
|
||
margin: EdgeInsets.symmetric(horizontal: 15.w, vertical: 8.w),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
// textDirection: message.isSelf ? TextDirection.rtl : TextDirection.ltr,
|
||
children: <Widget>[
|
||
Visibility(
|
||
visible: showTime,
|
||
child: Container(
|
||
margin: EdgeInsets.only(bottom: 12.w),
|
||
child: Row(
|
||
children: <Widget>[
|
||
Spacer(),
|
||
Container(
|
||
alignment: Alignment.center,
|
||
padding: EdgeInsets.symmetric(
|
||
horizontal: width(15),
|
||
vertical: 8.w,
|
||
),
|
||
decoration: BoxDecoration(
|
||
color: Colors.black12,
|
||
borderRadius: BorderRadius.all(
|
||
Radius.circular(height(13)),
|
||
),
|
||
),
|
||
child: Text(
|
||
time,
|
||
style: TextStyle(
|
||
fontSize: sp(12),
|
||
color: Colors.white,
|
||
fontWeight: FontWeight.w400,
|
||
decoration: TextDecoration.none,
|
||
height: 1,
|
||
),
|
||
),
|
||
),
|
||
Spacer(),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
if (cpRelationFormedCard != null)
|
||
cpRelationFormedCard
|
||
else if (cpStatusLineText != null)
|
||
_buildCpStatusLine(cpStatusLineText)
|
||
else
|
||
Row(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
textDirection:
|
||
message.isSelf! ? TextDirection.rtl : TextDirection.ltr,
|
||
children: <Widget>[
|
||
GestureDetector(
|
||
behavior: HitTestBehavior.opaque,
|
||
onTap: () {},
|
||
child:
|
||
noticeType == SCSysytemMessageType.CP_LOVE_LETTER.name &&
|
||
tagHead.isNotEmpty
|
||
? netImage(
|
||
url: tagHead,
|
||
width: 45.w,
|
||
shape: BoxShape.circle,
|
||
)
|
||
: ExtendedImage.asset(
|
||
SCGlobalConfig.businessLogicStrategy
|
||
.getMessagePageSystemMessageIcon(),
|
||
width: 45.w,
|
||
shape: BoxShape.circle,
|
||
fit: BoxFit.cover,
|
||
),
|
||
),
|
||
// 他人消息的阴影间隔是10dp
|
||
Container(width: 8.w),
|
||
Expanded(
|
||
child: Row(
|
||
textDirection: TextDirection.ltr,
|
||
children: <Widget>[
|
||
Expanded(
|
||
child: Container(
|
||
alignment: AlignmentDirectional.topStart,
|
||
margin: EdgeInsets.only(top: 4.w),
|
||
child: _msg(),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildCpStatusLine(String text) {
|
||
return SizedBox(
|
||
width: double.infinity,
|
||
child: Center(
|
||
child: Text(
|
||
text,
|
||
textAlign: TextAlign.center,
|
||
style: TextStyle(
|
||
fontSize: sp(14),
|
||
height: 1.2,
|
||
color: const Color(0xff999999),
|
||
fontWeight: FontWeight.w700,
|
||
decoration: TextDecoration.none,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildCpBuildMessage(
|
||
Map<String, dynamic> data,
|
||
Function(BuildContext ct, String content) showMsgItemMenu,
|
||
SCSystemInvitMessageRes? cpInvite,
|
||
) {
|
||
final state = _cpInviteStateForMessage(data);
|
||
final actionState = _cpInviteActionState(state);
|
||
final subtitle = _cpInviteMessageSubtitle(state);
|
||
final giftCover = cpInvite?.giftCover?.trim() ?? "";
|
||
return Builder(
|
||
builder: (ct) {
|
||
return GestureDetector(
|
||
onLongPress: () {
|
||
showMsgItemMenu(ct, "");
|
||
},
|
||
onTap: () {
|
||
_openCpInviteDialogFromMessage(data, cpInvite, actionState);
|
||
},
|
||
child: Container(
|
||
width: 251.w,
|
||
height: 64.w,
|
||
decoration: const BoxDecoration(color: Color(0xff071D1A)),
|
||
child: Stack(
|
||
children: [
|
||
Positioned(
|
||
left: 0,
|
||
top: 6.w,
|
||
child: Image.asset(
|
||
'sc_images/room/cp_invite/sc_cp_system_notice_bg.png',
|
||
width: 251.w,
|
||
height: 53.w,
|
||
fit: BoxFit.fill,
|
||
),
|
||
),
|
||
Positioned(
|
||
left: 14.w,
|
||
top: 15.w,
|
||
child: _buildCpInviteGiftThumb(giftCover),
|
||
),
|
||
Positioned(
|
||
left: 75.w,
|
||
top: 18.w,
|
||
child: SizedBox(
|
||
width: 160.w,
|
||
child: Text(
|
||
SCAppLocalizations.of(
|
||
context,
|
||
)!.closeFriendInvitationTitle,
|
||
maxLines: 1,
|
||
overflow: TextOverflow.ellipsis,
|
||
style: TextStyle(
|
||
color: const Color(0xffFF2A70),
|
||
fontSize: 10.sp,
|
||
fontWeight: FontWeight.w500,
|
||
height: 1,
|
||
decoration: TextDecoration.none,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
Positioned(
|
||
left: 75.w,
|
||
top: 35.w,
|
||
child: SizedBox(
|
||
width: 160.w,
|
||
child: Text(
|
||
subtitle,
|
||
maxLines: 1,
|
||
overflow: TextOverflow.ellipsis,
|
||
style: TextStyle(
|
||
color: const Color(0xff67576F),
|
||
fontSize: 8.sp,
|
||
fontWeight: FontWeight.w400,
|
||
height: 1,
|
||
decoration: TextDecoration.none,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
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) {
|
||
final child =
|
||
giftCover.isNotEmpty
|
||
? netImage(
|
||
url: giftCover,
|
||
width: 49.w,
|
||
height: 49.w,
|
||
fit: BoxFit.cover,
|
||
defaultImg:
|
||
'sc_images/room/cp_profile/sc_cp_profile_gift_fallback.png',
|
||
)
|
||
: Image.asset(
|
||
'sc_images/room/cp_profile/sc_cp_profile_gift_fallback.png',
|
||
width: 49.w,
|
||
height: 49.w,
|
||
fit: BoxFit.cover,
|
||
);
|
||
return ClipRRect(borderRadius: BorderRadius.circular(6.w), child: child);
|
||
}
|
||
|
||
Widget? _cpRelationFormedMessageCard() {
|
||
final data = _customDataFromMessage(message);
|
||
if (data == null || !_isCpInvitePayload(data)) {
|
||
return null;
|
||
}
|
||
if (_cpInviteStateFromData(data) != _CpInviteMessageState.accepted) {
|
||
return null;
|
||
}
|
||
final cpInvite = _cpInviteFromMessageData(data);
|
||
final content = _cpContentMap(data);
|
||
final currentProfile = AccountStorage().getCurrentUser()?.userProfile;
|
||
final currentName = _cpDisplayName(
|
||
nickname: currentProfile?.userNickname,
|
||
account: currentProfile?.account,
|
||
fallback: currentProfile?.id,
|
||
);
|
||
final inviterName = _cpDisplayName(
|
||
nickname: _firstNonBlankString([
|
||
cpInvite?.userNickname,
|
||
data["applyNickname"]?.toString(),
|
||
data["applyUserNickname"]?.toString(),
|
||
data["userNickname"]?.toString(),
|
||
data["senderNickname"]?.toString(),
|
||
content["applyNickname"]?.toString(),
|
||
content["applyUserNickname"]?.toString(),
|
||
content["userNickname"]?.toString(),
|
||
content["senderNickname"]?.toString(),
|
||
], fallback: ""),
|
||
account: _firstNonBlankString([
|
||
cpInvite?.account,
|
||
data["account"]?.toString(),
|
||
data["applyUserAccount"]?.toString(),
|
||
content["account"]?.toString(),
|
||
content["applyUserAccount"]?.toString(),
|
||
], fallback: ""),
|
||
actualAccount: _firstNonBlankString([
|
||
cpInvite?.actualAccount,
|
||
data["actualAccount"]?.toString(),
|
||
data["applyUserId"]?.toString(),
|
||
content["actualAccount"]?.toString(),
|
||
content["applyUserId"]?.toString(),
|
||
], fallback: ""),
|
||
fallback: message.sender,
|
||
);
|
||
final inviterAvatar = _firstNonBlankString([
|
||
cpInvite?.userAvatar,
|
||
data["applyUserAvatar"]?.toString(),
|
||
data["userAvatar"]?.toString(),
|
||
data["senderAvatar"]?.toString(),
|
||
content["applyUserAvatar"]?.toString(),
|
||
content["userAvatar"]?.toString(),
|
||
content["senderAvatar"]?.toString(),
|
||
], fallback: "");
|
||
final receiverName = _cpDisplayName(
|
||
nickname: _firstNonBlankString([
|
||
data["acceptNickname"]?.toString(),
|
||
data["acceptUserNickname"]?.toString(),
|
||
data["receiverNickname"]?.toString(),
|
||
data["receiverUserNickname"]?.toString(),
|
||
content["acceptNickname"]?.toString(),
|
||
content["acceptUserNickname"]?.toString(),
|
||
content["receiverNickname"]?.toString(),
|
||
content["receiverUserNickname"]?.toString(),
|
||
], fallback: ""),
|
||
account: _firstNonBlankString([
|
||
data["acceptAccount"]?.toString(),
|
||
data["receiverAccount"]?.toString(),
|
||
content["acceptAccount"]?.toString(),
|
||
content["receiverAccount"]?.toString(),
|
||
], fallback: ""),
|
||
actualAccount: _firstNonBlankString([
|
||
data["acceptActualAccount"]?.toString(),
|
||
data["acceptUserId"]?.toString(),
|
||
data["receiverActualAccount"]?.toString(),
|
||
data["receiverUserId"]?.toString(),
|
||
content["acceptActualAccount"]?.toString(),
|
||
content["acceptUserId"]?.toString(),
|
||
content["receiverActualAccount"]?.toString(),
|
||
content["receiverUserId"]?.toString(),
|
||
], fallback: ""),
|
||
fallback: currentName,
|
||
);
|
||
final receiverAvatar = _firstNonBlankString([
|
||
data["acceptUserAvatar"]?.toString(),
|
||
data["receiverAvatar"]?.toString(),
|
||
data["receiverUserAvatar"]?.toString(),
|
||
content["acceptUserAvatar"]?.toString(),
|
||
content["receiverAvatar"]?.toString(),
|
||
content["receiverUserAvatar"]?.toString(),
|
||
], fallback: currentProfile?.userAvatar ?? "");
|
||
final isInviter = _isCurrentUserCpInviter(data);
|
||
final relationType = scNormalizeCpRelationType(
|
||
_firstNonBlankString([
|
||
cpInvite?.relationType,
|
||
data["relationType"]?.toString(),
|
||
data["relation_type"]?.toString(),
|
||
content["relationType"]?.toString(),
|
||
content["relation_type"]?.toString(),
|
||
], fallback: "CP"),
|
||
);
|
||
|
||
return Builder(
|
||
builder: (ct) {
|
||
return GestureDetector(
|
||
onLongPress: () => _showMsgItemMenu(ct, ""),
|
||
child: SizedBox(
|
||
width: double.infinity,
|
||
child: Center(
|
||
child: RoomCpRelationFormedCard(
|
||
leftName: isInviter ? currentName : inviterName,
|
||
rightName: isInviter ? receiverName : currentName,
|
||
leftAvatar:
|
||
isInviter
|
||
? currentProfile?.userAvatar ?? ""
|
||
: inviterAvatar,
|
||
rightAvatar:
|
||
isInviter
|
||
? receiverAvatar
|
||
: currentProfile?.userAvatar ?? "",
|
||
relationType: relationType,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
void _showCpInviteDialogFromMessage(
|
||
Map<String, dynamic> data,
|
||
SCSystemInvitMessageRes? cpInvite,
|
||
RoomCpInviteActionState actionState,
|
||
) {
|
||
final currentProfile = AccountStorage().getCurrentUser()?.userProfile;
|
||
final currentName = _cpDisplayName(
|
||
nickname: currentProfile?.userNickname,
|
||
account: currentProfile?.account,
|
||
fallback: currentProfile?.id,
|
||
);
|
||
final inviterName = _cpDisplayName(
|
||
nickname: cpInvite?.userNickname,
|
||
account: cpInvite?.account,
|
||
actualAccount: cpInvite?.actualAccount,
|
||
);
|
||
final isInviter = _isCurrentUserCpInviter(data);
|
||
final content = _cpContentMap(data);
|
||
final receiverName =
|
||
isInviter
|
||
? _cpDisplayName(
|
||
nickname: _firstNonBlankString([
|
||
data["acceptNickname"]?.toString(),
|
||
data["acceptUserNickname"]?.toString(),
|
||
content["acceptNickname"]?.toString(),
|
||
content["acceptUserNickname"]?.toString(),
|
||
], fallback: ""),
|
||
account: _firstNonBlankString([
|
||
data["acceptAccount"]?.toString(),
|
||
content["acceptAccount"]?.toString(),
|
||
], fallback: ""),
|
||
actualAccount: _firstNonBlankString([
|
||
data["acceptActualAccount"]?.toString(),
|
||
content["acceptActualAccount"]?.toString(),
|
||
data["acceptUserId"]?.toString(),
|
||
content["acceptUserId"]?.toString(),
|
||
], fallback: ""),
|
||
fallback: "User",
|
||
)
|
||
: currentName;
|
||
final relationType = scNormalizeCpRelationType(cpInvite?.relationType);
|
||
final applyId = _cpApplyIdFromData(data);
|
||
RoomCpInviteDialog.show(
|
||
context,
|
||
inviter: RoomCpInviteDialogUser(
|
||
name: inviterName,
|
||
avatarUrl: cpInvite?.userAvatar ?? "",
|
||
headdress:
|
||
isInviter
|
||
? currentProfile?.getHeaddress()?.sourceUrl ?? ""
|
||
: _firstNonBlankString([
|
||
cpInvite?.userHeaddress,
|
||
data["userHeaddress"]?.toString(),
|
||
data["userAvatarFrame"]?.toString(),
|
||
content["userHeaddress"]?.toString(),
|
||
content["userAvatarFrame"]?.toString(),
|
||
], fallback: ""),
|
||
headdressCover:
|
||
isInviter
|
||
? currentProfile?.getHeaddress()?.cover ?? ""
|
||
: _firstNonBlankString([
|
||
cpInvite?.userHeaddressCover,
|
||
data["userHeaddressCover"]?.toString(),
|
||
data["userAvatarFrameCover"]?.toString(),
|
||
content["userHeaddressCover"]?.toString(),
|
||
content["userAvatarFrameCover"]?.toString(),
|
||
], fallback: ""),
|
||
),
|
||
receiver: RoomCpInviteDialogUser(
|
||
name: receiverName,
|
||
avatarUrl:
|
||
isInviter
|
||
? _firstNonBlankString([
|
||
data["acceptUserAvatar"]?.toString(),
|
||
content["acceptUserAvatar"]?.toString(),
|
||
], fallback: "")
|
||
: currentProfile?.userAvatar ?? "",
|
||
headdress:
|
||
isInviter
|
||
? _firstNonBlankString([
|
||
data["acceptHeaddress"]?.toString(),
|
||
data["acceptAvatarFrame"]?.toString(),
|
||
content["acceptHeaddress"]?.toString(),
|
||
content["acceptAvatarFrame"]?.toString(),
|
||
], fallback: "")
|
||
: currentProfile?.getHeaddress()?.sourceUrl ?? "",
|
||
headdressCover:
|
||
isInviter
|
||
? _firstNonBlankString([
|
||
data["acceptHeaddressCover"]?.toString(),
|
||
data["acceptAvatarFrameCover"]?.toString(),
|
||
content["acceptHeaddressCover"]?.toString(),
|
||
content["acceptAvatarFrameCover"]?.toString(),
|
||
], fallback: "")
|
||
: currentProfile?.getHeaddress()?.cover ?? "",
|
||
),
|
||
style:
|
||
isInviter
|
||
? RoomCpInviteDialogStyle.waiting
|
||
: RoomCpInviteDialogStyle.incoming,
|
||
actionState: actionState,
|
||
countdownSeconds: _cpInviteSecondsLeft(data),
|
||
descriptionText: _cpInviteDescriptionText(relationType),
|
||
onAccept:
|
||
!isInviter &&
|
||
actionState == RoomCpInviteActionState.pending &&
|
||
applyId.isNotEmpty
|
||
? () => acceptOpt(
|
||
applyId,
|
||
SCSysytemMessageType.CP_BUILD.name,
|
||
cpInvite: cpInvite,
|
||
cpData: data,
|
||
)
|
||
: null,
|
||
onReject:
|
||
!isInviter &&
|
||
actionState == RoomCpInviteActionState.pending &&
|
||
applyId.isNotEmpty
|
||
? () => rejectOpt(
|
||
applyId,
|
||
SCSysytemMessageType.CP_BUILD.name,
|
||
cpInvite: cpInvite,
|
||
cpData: data,
|
||
)
|
||
: null,
|
||
);
|
||
}
|
||
|
||
String? _cpStatusLineTextForMessage() {
|
||
final data = _customDataFromMessage(message);
|
||
if (data == null) {
|
||
return null;
|
||
}
|
||
final noticeType = data["noticeType"]?.toString() ?? "";
|
||
if (noticeType == SCSysytemMessageType.CP_BUILD.name) {
|
||
return null;
|
||
}
|
||
final state = _cpInviteStateFromData(data);
|
||
if (state == _CpInviteMessageState.pending || !_isCpInvitePayload(data)) {
|
||
return null;
|
||
}
|
||
final localizations = SCAppLocalizations.of(context)!;
|
||
if (state == _CpInviteMessageState.expired) {
|
||
return localizations.closeFriendInviteTimedOut;
|
||
}
|
||
final inviterView = _isCurrentUserCpInviter(data);
|
||
if (state == _CpInviteMessageState.accepted) {
|
||
return null;
|
||
}
|
||
return inviterView
|
||
? localizations.otherDeclinedCloseFriendInvite
|
||
: localizations.youDeclinedCloseFriendInvite;
|
||
}
|
||
|
||
Map<String, dynamic>? _customDataFromMessage(V2TimMessage msg) {
|
||
if (msg.elemType != MessageElemType.V2TIM_ELEM_TYPE_CUSTOM) {
|
||
return null;
|
||
}
|
||
final raw = msg.customElem?.data;
|
||
if (raw == null || raw.trim().isEmpty) {
|
||
return null;
|
||
}
|
||
try {
|
||
final decoded = jsonDecode(raw);
|
||
if (decoded is Map) {
|
||
return decoded.map((key, value) => MapEntry(key.toString(), value));
|
||
}
|
||
} catch (_) {}
|
||
return null;
|
||
}
|
||
|
||
_CpInviteMessageState _cpInviteStateForMessage(Map<String, dynamic> data) {
|
||
final explicitState = _cpInviteStateFromConversation(data);
|
||
if (explicitState != _CpInviteMessageState.pending) {
|
||
return explicitState;
|
||
}
|
||
return _cpInviteSecondsLeft(data) <= 0
|
||
? _CpInviteMessageState.expired
|
||
: _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(
|
||
Map<String, dynamic> currentData,
|
||
) {
|
||
final applyId = _cpApplyIdFromData(currentData);
|
||
final currentState = _cpInviteStateFromData(currentData);
|
||
if (currentState != _CpInviteMessageState.pending || applyId.isEmpty) {
|
||
return currentState;
|
||
}
|
||
final currentTimestamp = message.timestamp ?? 0;
|
||
for (final item in currentConversationMessageList) {
|
||
if ((item.timestamp ?? 0) < currentTimestamp) {
|
||
continue;
|
||
}
|
||
final data = _customDataFromMessage(item);
|
||
if (data == null || _cpApplyIdFromData(data) != applyId) {
|
||
continue;
|
||
}
|
||
final state = _cpInviteStateFromData(data);
|
||
if (state != _CpInviteMessageState.pending) {
|
||
return state;
|
||
}
|
||
}
|
||
return _CpInviteMessageState.pending;
|
||
}
|
||
|
||
_CpInviteMessageState _cpInviteStateFromData(Map<String, dynamic> data) {
|
||
final content = _cpContentMap(data);
|
||
final values = <String>[
|
||
data["noticeType"]?.toString() ?? "",
|
||
data["type"]?.toString() ?? "",
|
||
data["noticeAction"]?.toString() ?? "",
|
||
data["action"]?.toString() ?? "",
|
||
data["status"]?.toString() ?? "",
|
||
data["applyStatus"]?.toString() ?? "",
|
||
data["processStatus"]?.toString() ?? "",
|
||
data["result"]?.toString() ?? "",
|
||
data["state"]?.toString() ?? "",
|
||
content["noticeType"]?.toString() ?? "",
|
||
content["type"]?.toString() ?? "",
|
||
content["noticeAction"]?.toString() ?? "",
|
||
content["action"]?.toString() ?? "",
|
||
content["status"]?.toString() ?? "",
|
||
content["applyStatus"]?.toString() ?? "",
|
||
content["processStatus"]?.toString() ?? "",
|
||
content["result"]?.toString() ?? "",
|
||
content["state"]?.toString() ?? "",
|
||
].map((value) => value.trim().toUpperCase()).join("|");
|
||
final expiredValue = _cpInviteBoolValue([
|
||
data["expired"],
|
||
data["isExpired"],
|
||
content["expired"],
|
||
content["isExpired"],
|
||
]);
|
||
if (expiredValue == true) {
|
||
return _CpInviteMessageState.expired;
|
||
}
|
||
final agreeValue = _cpInviteBoolValue([
|
||
data["agree"],
|
||
data["accepted"],
|
||
data["isAgree"],
|
||
content["agree"],
|
||
content["accepted"],
|
||
content["isAgree"],
|
||
]);
|
||
if (agreeValue == true) {
|
||
return _CpInviteMessageState.accepted;
|
||
}
|
||
if (agreeValue == false) {
|
||
return _CpInviteMessageState.rejected;
|
||
}
|
||
if (values.contains("TIMEOUT") || values.contains("EXPIRE")) {
|
||
return _CpInviteMessageState.expired;
|
||
}
|
||
if (values.contains("REJECT") ||
|
||
values.contains("DECLIN") ||
|
||
values.contains("REFUSE") ||
|
||
values.contains("DENY")) {
|
||
return _CpInviteMessageState.rejected;
|
||
}
|
||
if (values.contains("ACCEPT") ||
|
||
values.contains("AGREE") ||
|
||
values.contains("APPROVE") ||
|
||
values.contains("ESTABLISH")) {
|
||
return _CpInviteMessageState.accepted;
|
||
}
|
||
return _CpInviteMessageState.pending;
|
||
}
|
||
|
||
bool? _cpInviteBoolValue(Iterable<dynamic> values) {
|
||
for (final value in values) {
|
||
if (value is bool) {
|
||
return value;
|
||
}
|
||
final text = value?.toString().trim().toLowerCase() ?? "";
|
||
if (text.isEmpty) {
|
||
continue;
|
||
}
|
||
if (text == "true" || text == "1" || text == "yes" || text == "agree") {
|
||
return true;
|
||
}
|
||
if (text == "false" ||
|
||
text == "0" ||
|
||
text == "no" ||
|
||
text == "reject" ||
|
||
text == "decline" ||
|
||
text == "refuse") {
|
||
return false;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
bool _isCpInvitePayload(Map<String, dynamic> data) {
|
||
final content = _cpContentMap(data);
|
||
final text =
|
||
<String>[
|
||
data["noticeType"]?.toString() ?? "",
|
||
data["type"]?.toString() ?? "",
|
||
data["relationType"]?.toString() ?? "",
|
||
content["noticeType"]?.toString() ?? "",
|
||
content["type"]?.toString() ?? "",
|
||
content["relationType"]?.toString() ?? "",
|
||
].join("|").toUpperCase();
|
||
return text.contains("CP") ||
|
||
text.contains("BROTHER") ||
|
||
text.contains("SISTER");
|
||
}
|
||
|
||
bool _isCurrentUserCpInviter(Map<String, dynamic> data) {
|
||
final currentProfile = AccountStorage().getCurrentUser()?.userProfile;
|
||
if (currentProfile == null) {
|
||
return false;
|
||
}
|
||
final content = _cpContentMap(data);
|
||
final inviterIds =
|
||
<String>[
|
||
data["applyUserId"]?.toString() ?? "",
|
||
data["applyUserAccount"]?.toString() ?? "",
|
||
data["account"]?.toString() ?? "",
|
||
data["actualAccount"]?.toString() ?? "",
|
||
content["applyUserId"]?.toString() ?? "",
|
||
content["applyUserAccount"]?.toString() ?? "",
|
||
content["account"]?.toString() ?? "",
|
||
content["actualAccount"]?.toString() ?? "",
|
||
]
|
||
.map((value) => value.trim())
|
||
.where((value) => value.isNotEmpty)
|
||
.toSet();
|
||
return inviterIds.contains(currentProfile.id?.trim() ?? "") ||
|
||
inviterIds.contains(currentProfile.account?.trim() ?? "");
|
||
}
|
||
|
||
int _cpInviteSecondsLeft(Map<String, dynamic> data) {
|
||
final content = _cpContentMap(data);
|
||
final now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||
final explicitExpireAt = _firstEpochSeconds([
|
||
data["expireTime"],
|
||
data["expiredTime"],
|
||
data["expireAt"],
|
||
data["expiredAt"],
|
||
data["timeoutAt"],
|
||
data["endTime"],
|
||
content["expireTime"],
|
||
content["expiredTime"],
|
||
content["expireAt"],
|
||
content["expiredAt"],
|
||
content["timeoutAt"],
|
||
content["endTime"],
|
||
]);
|
||
if (explicitExpireAt != null) {
|
||
return (explicitExpireAt - now).clamp(0, 86400).toInt();
|
||
}
|
||
final startAt =
|
||
_firstEpochSeconds([
|
||
data["createTime"],
|
||
data["createdAt"],
|
||
data["sendTime"],
|
||
content["createTime"],
|
||
content["createdAt"],
|
||
content["sendTime"],
|
||
]) ??
|
||
(message.timestamp ?? now);
|
||
return (startAt + 86400 - now).clamp(0, 86400).toInt();
|
||
}
|
||
|
||
int? _firstEpochSeconds(Iterable<dynamic> values) {
|
||
for (final value in values) {
|
||
final text = value?.toString().trim() ?? "";
|
||
if (text.isEmpty) {
|
||
continue;
|
||
}
|
||
final parsed = num.tryParse(text);
|
||
if (parsed == null || parsed <= 0) {
|
||
continue;
|
||
}
|
||
final seconds = parsed > 9999999999 ? parsed ~/ 1000 : parsed.toInt();
|
||
return seconds;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
String _cpApplyIdFromData(Map<String, dynamic> data) {
|
||
final content = _cpContentMap(data);
|
||
return _firstNonBlankString([
|
||
data["expand"]?.toString(),
|
||
data["applyId"]?.toString(),
|
||
data["apply_id"]?.toString(),
|
||
data["id"]?.toString(),
|
||
content["expand"]?.toString(),
|
||
content["applyId"]?.toString(),
|
||
content["apply_id"]?.toString(),
|
||
content["id"]?.toString(),
|
||
], fallback: "");
|
||
}
|
||
|
||
Map<String, dynamic> _cpContentMap(Map<String, dynamic> data) {
|
||
final content = data["content"];
|
||
try {
|
||
if (content is String && content.trim().isNotEmpty) {
|
||
final decoded = jsonDecode(content);
|
||
if (decoded is Map) {
|
||
return decoded.map((key, value) => MapEntry(key.toString(), value));
|
||
}
|
||
}
|
||
if (content is Map) {
|
||
return content.map((key, value) => MapEntry(key.toString(), value));
|
||
}
|
||
} catch (_) {}
|
||
return const <String, dynamic>{};
|
||
}
|
||
|
||
RoomCpInviteActionState _cpInviteActionState(_CpInviteMessageState state) {
|
||
switch (state) {
|
||
case _CpInviteMessageState.expired:
|
||
return RoomCpInviteActionState.expired;
|
||
case _CpInviteMessageState.rejected:
|
||
return RoomCpInviteActionState.rejected;
|
||
case _CpInviteMessageState.accepted:
|
||
return RoomCpInviteActionState.accepted;
|
||
case _CpInviteMessageState.pending:
|
||
return RoomCpInviteActionState.pending;
|
||
}
|
||
}
|
||
|
||
String _cpInviteMessageSubtitle(_CpInviteMessageState state) {
|
||
final localizations = SCAppLocalizations.of(context)!;
|
||
switch (state) {
|
||
case _CpInviteMessageState.expired:
|
||
return localizations.closeFriendInviteTimedOut;
|
||
case _CpInviteMessageState.rejected:
|
||
return localizations.closeFriendRequestDeclined;
|
||
case _CpInviteMessageState.accepted:
|
||
return localizations.closeFriendsHaveBecome;
|
||
case _CpInviteMessageState.pending:
|
||
return localizations.closeFriendInvitationSubtitle;
|
||
}
|
||
}
|
||
|
||
String _cpInviteDescriptionText(String relationType) {
|
||
switch (scNormalizeCpRelationType(relationType)) {
|
||
case "BROTHER":
|
||
return 'Invite you to become Brothers';
|
||
case "SISTERS":
|
||
return 'Invite you to become Sisters';
|
||
case "CP":
|
||
default:
|
||
return 'Invite you to become Couple';
|
||
}
|
||
}
|
||
|
||
String _cpDisplayName({
|
||
String? nickname,
|
||
String? account,
|
||
String? actualAccount,
|
||
String? fallback,
|
||
}) {
|
||
return _firstNonBlankString([nickname, actualAccount, account, fallback]);
|
||
}
|
||
|
||
String _firstNonBlankString(
|
||
Iterable<String?> values, {
|
||
String fallback = "User",
|
||
}) {
|
||
for (final value in values) {
|
||
final text = value?.trim() ?? "";
|
||
if (text.isNotEmpty) {
|
||
return text;
|
||
}
|
||
}
|
||
return fallback;
|
||
}
|
||
|
||
_msg() {
|
||
return _text();
|
||
}
|
||
|
||
///文本消息
|
||
_text() {
|
||
String content = "";
|
||
if (message.elemType == MessageElemType.V2TIM_ELEM_TYPE_TEXT) {
|
||
V2TimTextElem textElem = message.textElem!;
|
||
content = textElem.text ?? "";
|
||
} else if (message.elemType == MessageElemType.V2TIM_ELEM_TYPE_IMAGE) {
|
||
content = SCAppLocalizations.of(context)!.image;
|
||
} else if (message.elemType == MessageElemType.V2TIM_ELEM_TYPE_VIDEO) {
|
||
content = SCAppLocalizations.of(context)!.video;
|
||
} else if (message.elemType == MessageElemType.V2TIM_ELEM_TYPE_SOUND) {
|
||
content = SCAppLocalizations.of(context)!.sound;
|
||
} else if (message.elemType == MessageElemType.V2TIM_ELEM_TYPE_CUSTOM) {
|
||
V2TimCustomElem customElem = message.customElem!;
|
||
content = customElem.data ?? "";
|
||
final data = jsonDecode(content);
|
||
String type = data["noticeType"];
|
||
if (type == SCSysytemMessageType.GIVE_AWAY_PROPS.name) {
|
||
String title = data["title"] ?? "";
|
||
String expand = data["expand"] ?? "";
|
||
return Builder(
|
||
builder: (ct) {
|
||
return GestureDetector(
|
||
child: Container(
|
||
decoration: BoxDecoration(
|
||
color: Color(0xff18F2B1).withOpacity(0.1),
|
||
borderRadius: BorderRadius.only(
|
||
topLeft: Radius.circular(0),
|
||
topRight: Radius.circular(8.w),
|
||
bottomLeft: Radius.circular(8.w),
|
||
bottomRight: Radius.circular(8),
|
||
),
|
||
),
|
||
padding: EdgeInsets.all(8.0.w),
|
||
child: Column(
|
||
children: [
|
||
text(
|
||
SCAppLocalizations.of(context)!.propMessagePrompt,
|
||
maxLines: 1,
|
||
// specialTextSpanBuilder: MySpecialTextSpanBuilder(),
|
||
fontSize: sp(16),
|
||
textColor: Colors.white,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
ExtendedText(
|
||
data["content"],
|
||
// specialTextSpanBuilder: MySpecialTextSpanBuilder(),
|
||
style: TextStyle(fontSize: sp(14), color: Colors.white),
|
||
),
|
||
expand.isNotEmpty
|
||
? Row(
|
||
children: [
|
||
SizedBox(width: 10.w),
|
||
netImage(
|
||
url: expand,
|
||
width: 45.w,
|
||
height: 45.w,
|
||
fit: BoxFit.contain,
|
||
),
|
||
],
|
||
)
|
||
: Container(),
|
||
],
|
||
),
|
||
),
|
||
onTap: () {
|
||
if (title.isNotEmpty) {
|
||
var dTitle = jsonDecode(title);
|
||
String propType = dTitle["propType"] ?? "";
|
||
if ("ACTIVITY" == propType ||
|
||
"ADMINISTRSCOR" == propType ||
|
||
"ACHIEVEMENT" == propType) {
|
||
} else {
|
||
SCNavigatorUtils.push(
|
||
context,
|
||
StoreRoute.bags,
|
||
replace: false,
|
||
);
|
||
}
|
||
} else {
|
||
SCNavigatorUtils.push(
|
||
context,
|
||
StoreRoute.bags,
|
||
replace: false,
|
||
);
|
||
}
|
||
},
|
||
onLongPress: () {
|
||
_showMsgItemMenu(ct, "");
|
||
},
|
||
);
|
||
},
|
||
);
|
||
} else if (type == SCSysytemMessageType.AGENT_SEND_INVITE_HOST.name) {
|
||
return SCSystemMessageUtils.buildAgentSendInviteHostMessage(
|
||
data,
|
||
(ct, content) {
|
||
_showMsgItemMenu(ct, content);
|
||
},
|
||
(String id) {
|
||
rejectOpt(id, type);
|
||
},
|
||
(String id) {
|
||
acceptOpt(id, type);
|
||
},
|
||
context,
|
||
);
|
||
} else if (type == SCSysytemMessageType.BD_SEND_INVITE_AGENT.name) {
|
||
return SCSystemMessageUtils.buildBdSendInviteAgentMessage(
|
||
data,
|
||
(ct, content) {
|
||
_showMsgItemMenu(ct, content);
|
||
},
|
||
(String id) {
|
||
rejectOpt(id, type);
|
||
},
|
||
(String id) {
|
||
acceptOpt(id, type);
|
||
},
|
||
context,
|
||
);
|
||
} else if (type == SCSysytemMessageType.BD_LEADER_INVITE_BD.name) {
|
||
return SCSystemMessageUtils.buildBdLeaderInviteBdMessage(
|
||
data,
|
||
(ct, content) {
|
||
_showMsgItemMenu(ct, content);
|
||
},
|
||
(String id) {
|
||
rejectOpt(id, type);
|
||
},
|
||
(String id) {
|
||
acceptOpt(id, type);
|
||
},
|
||
context,
|
||
);
|
||
} else if (type == SCSysytemMessageType.BD_LEADER_INVITE_BD_LEADER.name) {
|
||
return SCSystemMessageUtils.buildBdLeaderInviteBdLeaderMessage(
|
||
data,
|
||
(ct, content) {
|
||
_showMsgItemMenu(ct, content);
|
||
},
|
||
(String id) {
|
||
rejectOpt(id, type);
|
||
},
|
||
(String id) {
|
||
acceptOpt(id, type);
|
||
},
|
||
context,
|
||
);
|
||
} else if (type ==
|
||
SCSysytemMessageType.ADMIN_INVITE_RECHARGE_AGENT.name) {
|
||
return SCSystemMessageUtils.buildAdminInviteRechargeAgentMessage(
|
||
data,
|
||
(ct, content) {
|
||
_showMsgItemMenu(ct, content);
|
||
},
|
||
(String id) {
|
||
rejectOpt(id, type);
|
||
},
|
||
(String id) {
|
||
acceptOpt(id, type);
|
||
},
|
||
context,
|
||
);
|
||
} else if (type == SCSysytemMessageType.CP_BUILD.name) {
|
||
final cpInvite = _cpInviteFromMessageData(data);
|
||
return _buildCpBuildMessage(data, (ct, content) {
|
||
_showMsgItemMenu(ct, content);
|
||
}, cpInvite);
|
||
} else if (type == SCSysytemMessageType.CP_LOVE_LETTER.name) {
|
||
return SCSystemMessageUtils.buildCPLoveLetterMessage(data, (
|
||
ct,
|
||
content,
|
||
) {
|
||
_showMsgItemMenu(ct, content);
|
||
}, context);
|
||
} else if (type == SCSysytemMessageType.CP_DISMISS.name ||
|
||
type == SCSysytemMessageType.CP_BLESS.name) {
|
||
return SCSystemMessageUtils.buildCPNoticeMessage(data, (ct, content) {
|
||
_showMsgItemMenu(ct, content);
|
||
}, context);
|
||
} else if (type == SCSysytemMessageType.USER_COINS_RECEIVED.name) {
|
||
return SCSystemMessageUtils.buildUserCoinsReceivedMessage(data, (
|
||
ct,
|
||
content,
|
||
) {
|
||
_showMsgItemMenu(ct, content);
|
||
}, context);
|
||
} else if (type == SCSysytemMessageType.COIN_SELLER_COINS_RECEIVED.name) {
|
||
return SCSystemMessageUtils.buildUserCoinsReceivedMessage(data, (
|
||
ct,
|
||
content,
|
||
) {
|
||
_showMsgItemMenu(ct, content);
|
||
}, context);
|
||
} else if (_isRegisterRewardGrantedType(type)) {
|
||
return SCSystemMessageUtils.buildRegisterRewardGrantedMessage(data, (
|
||
ct,
|
||
content,
|
||
) {
|
||
_showMsgItemMenu(ct, content);
|
||
}, context);
|
||
} else if (type == SCSysytemMessageType.USER_SPECIAL_AUDIT_RESULTS.name) {
|
||
if (data["content"] != null) {
|
||
return Builder(
|
||
builder: (ct) {
|
||
return GestureDetector(
|
||
onLongPress: () {
|
||
_showMsgItemMenu(ct, "");
|
||
},
|
||
onTap: () {},
|
||
child: Container(
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
boxShadow: [
|
||
BoxShadow(blurRadius: 2.w, color: Colors.black26),
|
||
],
|
||
borderRadius: BorderRadius.only(
|
||
topLeft: Radius.circular(0),
|
||
topRight: Radius.circular(8.w),
|
||
bottomLeft: Radius.circular(8.w),
|
||
bottomRight: Radius.circular(8),
|
||
),
|
||
),
|
||
padding: EdgeInsets.all(8.0.w),
|
||
child: ExtendedText(
|
||
data["content"],
|
||
// specialTextSpanBuilder: MySpecialTextSpanBuilder(),
|
||
style: TextStyle(fontSize: sp(14), color: Colors.black54),
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
} else if (type == SCSysytemMessageType.USER_FOLLOW.name) {
|
||
String expand = data["expand"] ?? "";
|
||
if (data["content"] != null) {
|
||
var bean = SCSystemInvitMessageRes.fromJson(
|
||
jsonDecode(data["content"]),
|
||
);
|
||
return Builder(
|
||
builder: (ct) {
|
||
return GestureDetector(
|
||
onLongPress: () {
|
||
_showMsgItemMenu(ct, "");
|
||
},
|
||
child: Container(
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
boxShadow: [
|
||
BoxShadow(blurRadius: 2.w, color: Colors.black26),
|
||
],
|
||
borderRadius: BorderRadius.only(
|
||
topLeft: Radius.circular(0),
|
||
topRight: Radius.circular(8.w),
|
||
bottomLeft: Radius.circular(8.w),
|
||
bottomRight: Radius.circular(8),
|
||
),
|
||
),
|
||
padding: EdgeInsets.all(8.0.w),
|
||
child: Column(
|
||
children: [
|
||
Row(
|
||
children: [
|
||
head(url: bean.userAvatar ?? "", width: 65.w),
|
||
Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Row(
|
||
children: [
|
||
netImage(
|
||
url:
|
||
Provider.of<SCAppGeneralManager>(
|
||
context,
|
||
listen: false,
|
||
)
|
||
.findCountryByName(
|
||
bean.countryName ?? "",
|
||
)
|
||
?.nationalFlag ??
|
||
"",
|
||
borderRadius: BorderRadius.all(
|
||
Radius.circular(3.w),
|
||
),
|
||
width: 19.w,
|
||
height: 14.w,
|
||
),
|
||
SizedBox(width: 3.w),
|
||
Container(
|
||
constraints: BoxConstraints(
|
||
maxWidth: 160.w,
|
||
),
|
||
child: text(
|
||
bean.userNickname ?? "",
|
||
fontWeight: FontWeight.bold,
|
||
textColor: Colors.black,
|
||
fontSize: 16.sp,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
GestureDetector(
|
||
child: Container(
|
||
padding: EdgeInsets.symmetric(vertical: 8.w),
|
||
decoration: BoxDecoration(
|
||
image: DecorationImage(
|
||
image: AssetImage(
|
||
SCGlobalConfig.businessLogicStrategy
|
||
.getIdBackgroundImage(
|
||
bean.account !=
|
||
bean.actualAccount,
|
||
),
|
||
),
|
||
fit: BoxFit.fitWidth,
|
||
),
|
||
),
|
||
child: Row(
|
||
textDirection: TextDirection.ltr,
|
||
children: [
|
||
SizedBox(width: 38.w),
|
||
text(
|
||
bean.actualAccount ?? "",
|
||
fontSize: 12.sp,
|
||
textColor: Colors.white,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
SizedBox(width: 5.w),
|
||
Image.asset(
|
||
SCGlobalConfig.businessLogicStrategy
|
||
.getCopyIdIcon(),
|
||
width: 12.w,
|
||
height: 12.w,
|
||
),
|
||
SizedBox(width: 8.w),
|
||
],
|
||
),
|
||
),
|
||
onTap: () {
|
||
Clipboard.setData(
|
||
ClipboardData(
|
||
text: bean.actualAccount ?? "",
|
||
),
|
||
);
|
||
SCTts.show(
|
||
SCAppLocalizations.of(
|
||
context,
|
||
)!.copiedToClipboard,
|
||
);
|
||
},
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
SizedBox(height: 3.w),
|
||
GestureDetector(
|
||
child: Container(
|
||
alignment: AlignmentDirectional.center,
|
||
height: 25.w,
|
||
width: 65.w,
|
||
decoration: BoxDecoration(
|
||
color: Color(0xffB464FF),
|
||
borderRadius: BorderRadius.all(
|
||
Radius.circular(15.0),
|
||
),
|
||
),
|
||
child: text(
|
||
SCAppLocalizations.of(context)!.follow,
|
||
fontSize: 14.sp,
|
||
fontWeight: FontWeight.w600,
|
||
textColor: Colors.white,
|
||
),
|
||
),
|
||
onTap: () {
|
||
SCAccountRepository().followNew(expand).then((
|
||
result,
|
||
) {
|
||
SCTts.show(
|
||
SCAppLocalizations.of(context)!.followSucc,
|
||
);
|
||
});
|
||
},
|
||
),
|
||
Divider(
|
||
color: Colors.black12,
|
||
thickness: 0.5,
|
||
height: 28.w,
|
||
),
|
||
ExtendedText(
|
||
SCAppLocalizations.of(context)!.followedYou,
|
||
// specialTextSpanBuilder: MySpecialTextSpanBuilder(),
|
||
style: TextStyle(
|
||
fontSize: sp(14),
|
||
color: Colors.black54,
|
||
),
|
||
),
|
||
SizedBox(height: 5.w),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
} else if (type == SCSysytemMessageType.VIOLSCION_WARNING.name) {
|
||
if (data["content"] != null) {
|
||
return Builder(
|
||
builder: (ct) {
|
||
return GestureDetector(
|
||
onLongPress: () {
|
||
_showMsgItemMenu(ct, "");
|
||
},
|
||
onTap: () {},
|
||
child: Container(
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
boxShadow: [
|
||
BoxShadow(blurRadius: 2.w, color: Colors.black26),
|
||
],
|
||
borderRadius: BorderRadius.only(
|
||
topLeft: Radius.circular(0),
|
||
topRight: Radius.circular(8.w),
|
||
bottomLeft: Radius.circular(8.w),
|
||
bottomRight: Radius.circular(8),
|
||
),
|
||
),
|
||
padding: EdgeInsets.all(8.0.w),
|
||
child: ExtendedText(
|
||
data["content"],
|
||
// specialTextSpanBuilder: MySpecialTextSpanBuilder(),
|
||
style: TextStyle(fontSize: sp(14), color: Colors.black54),
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
} else if (type == SCSysytemMessageType.VIOLSCION_ADJUST.name) {
|
||
if (data["content"] != null) {
|
||
return Builder(
|
||
builder: (ct) {
|
||
return GestureDetector(
|
||
onLongPress: () {
|
||
_showMsgItemMenu(ct, "");
|
||
},
|
||
onTap: () {},
|
||
child: Container(
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
boxShadow: [
|
||
BoxShadow(blurRadius: 2.w, color: Colors.black26),
|
||
],
|
||
borderRadius: BorderRadius.only(
|
||
topLeft: Radius.circular(0),
|
||
topRight: Radius.circular(8.w),
|
||
bottomLeft: Radius.circular(8.w),
|
||
bottomRight: Radius.circular(8),
|
||
),
|
||
),
|
||
padding: EdgeInsets.all(8.0.w),
|
||
child: ExtendedText(
|
||
data["content"],
|
||
// specialTextSpanBuilder: MySpecialTextSpanBuilder(),
|
||
style: TextStyle(fontSize: sp(14), color: Colors.black54),
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
}
|
||
if (content.isEmpty) {
|
||
if (customElem.extension == 'sendGift') {
|
||
content = SCAppLocalizations.of(context)!.gift2;
|
||
} else {
|
||
content = SCAppLocalizations.of(context)!.receivedAMessage;
|
||
}
|
||
}
|
||
}
|
||
|
||
return Builder(
|
||
builder: (ct) {
|
||
return GestureDetector(
|
||
onLongPress: () {
|
||
_showMsgItemMenu(ct, "");
|
||
},
|
||
child: Container(
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
boxShadow: [BoxShadow(blurRadius: 2.w, color: Colors.black26)],
|
||
borderRadius: BorderRadius.only(
|
||
topLeft: Radius.circular(0),
|
||
topRight: Radius.circular(8.w),
|
||
bottomLeft: Radius.circular(8.w),
|
||
bottomRight: Radius.circular(8),
|
||
),
|
||
),
|
||
padding: EdgeInsets.all(8.0.w),
|
||
child: ExtendedText(
|
||
content,
|
||
// specialTextSpanBuilder: MySpecialTextSpanBuilder(),
|
||
style: TextStyle(fontSize: sp(14), color: Colors.black54),
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
bool _isRegisterRewardGrantedType(String type) {
|
||
return type.trim().toUpperCase().replaceAll(' ', '_') ==
|
||
SCSysytemMessageType.REGISTER_REWARD_GRANTED.name;
|
||
}
|
||
|
||
void _showMsgItemMenu(BuildContext ct, String content) {
|
||
SmartDialog.showAttach(
|
||
tag: "showMsgItemMenu",
|
||
targetContext: ct,
|
||
alignment: Alignment.topCenter,
|
||
maskColor: Colors.transparent,
|
||
animationType: SmartAnimationType.fade,
|
||
scalePointBuilder: (selfSize) => Offset(selfSize.width, 10),
|
||
builder: (_) {
|
||
return Container(
|
||
margin: EdgeInsets.only(bottom: 10.w),
|
||
decoration: BoxDecoration(
|
||
color: Color(0xffdcdddf),
|
||
borderRadius: BorderRadius.circular(10),
|
||
),
|
||
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 5.w),
|
||
child: Row(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
GestureDetector(
|
||
behavior: HitTestBehavior.opaque,
|
||
onTap: () {
|
||
SmartDialog.dismiss(tag: "showMsgItemMenu");
|
||
_delete();
|
||
},
|
||
child: Container(
|
||
margin: EdgeInsets.symmetric(horizontal: 8.w),
|
||
child: Column(
|
||
children: [
|
||
Image.asset(
|
||
SCGlobalConfig.businessLogicStrategy
|
||
.getSCMessageChatPageMessageMenuDeleteIcon(),
|
||
width: 20.w,
|
||
),
|
||
SizedBox(height: 3.w),
|
||
text(
|
||
SCAppLocalizations.of(context)!.delete,
|
||
fontSize: 12.sp,
|
||
textColor: Color(0xff777777),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
///删除消息
|
||
void _delete() {
|
||
SmartDialog.show(
|
||
tag: "showDeleteDialog",
|
||
alignment: Alignment.bottomCenter,
|
||
debounce: true,
|
||
animationType: SmartAnimationType.fade,
|
||
builder: (_) {
|
||
return SafeArea(
|
||
child: Container(
|
||
height: 168.w,
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.only(
|
||
topLeft: Radius.circular(8.0),
|
||
topRight: Radius.circular(8.0),
|
||
),
|
||
),
|
||
child: Column(
|
||
children: [
|
||
SizedBox(height: 10.w),
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
text(
|
||
SCAppLocalizations.of(context)!.tips,
|
||
fontSize: 16.sp,
|
||
textColor: Colors.black,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
],
|
||
),
|
||
SizedBox(height: 5.w),
|
||
Divider(height: height(1), color: SocialChatTheme.dividerColor),
|
||
GestureDetector(
|
||
child: Container(
|
||
padding: EdgeInsets.symmetric(vertical: 10.w),
|
||
color: Colors.transparent,
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
text(
|
||
SCAppLocalizations.of(context)!.deleteFromMyDevice,
|
||
fontSize: 14.sp,
|
||
textColor: Colors.black,
|
||
),
|
||
],
|
||
),
|
||
),
|
||
onTap: () async {
|
||
V2TimCallback deleteMessageFromLocalStorage =
|
||
await TencentImSDKPlugin.v2TIMManager
|
||
.getMessageManager()
|
||
.deleteMessageFromLocalStorage(
|
||
msgID: message.msgID ?? "",
|
||
);
|
||
if (deleteMessageFromLocalStorage.code == 0) {
|
||
//删除成功
|
||
int index = 0;
|
||
for (var value in currentConversationMessageList) {
|
||
if (value.msgID == message.msgID) {
|
||
break;
|
||
}
|
||
index = index + 1;
|
||
}
|
||
currentConversationMessageList.removeAt(index);
|
||
updateCall();
|
||
SmartDialog.dismiss(tag: "showDeleteDialog");
|
||
}
|
||
},
|
||
),
|
||
Divider(height: height(1), color: SocialChatTheme.dividerColor),
|
||
GestureDetector(
|
||
onTap: () async {
|
||
V2TimCallback deleteMessageFromLocalStorage =
|
||
await TencentImSDKPlugin.v2TIMManager
|
||
.getMessageManager()
|
||
.deleteMessages(msgIDs: [message.msgID ?? ""]);
|
||
if (deleteMessageFromLocalStorage.code == 0) {
|
||
//删除成功
|
||
int index = 0;
|
||
for (var value in currentConversationMessageList) {
|
||
if (value.msgID == message.msgID) {
|
||
break;
|
||
}
|
||
index = index + 1;
|
||
}
|
||
currentConversationMessageList.removeAt(index);
|
||
updateCall();
|
||
SmartDialog.dismiss(tag: "showDeleteDialog");
|
||
}
|
||
},
|
||
child: Container(
|
||
padding: EdgeInsets.symmetric(vertical: 10.w),
|
||
color: Colors.transparent,
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
text(
|
||
SCAppLocalizations.of(context)!.deleteOnAllDevices,
|
||
fontSize: 14.sp,
|
||
textColor: Colors.black,
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
Divider(height: height(1), color: SocialChatTheme.dividerColor),
|
||
GestureDetector(
|
||
onTap: () async {
|
||
SmartDialog.dismiss(tag: "showDeleteDialog");
|
||
},
|
||
child: Container(
|
||
padding: EdgeInsets.symmetric(vertical: 10.w),
|
||
color: Colors.transparent,
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
text(
|
||
SCAppLocalizations.of(context)!.cancel,
|
||
fontSize: 14.sp,
|
||
textColor: Colors.black,
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
SCSystemInvitMessageRes? _cpInviteFromMessageData(dynamic data) {
|
||
try {
|
||
return SCSystemInvitMessageRes.fromMessageData(data);
|
||
} catch (_) {}
|
||
return null;
|
||
}
|
||
|
||
Future<void> _acceptCpInviteDirect(
|
||
String id,
|
||
SCSystemInvitMessageRes? cpInvite,
|
||
Map<String, dynamic>? cpData,
|
||
) async {
|
||
if (!await _shouldProcessCpInvite(id, cpInvite, cpData)) {
|
||
return;
|
||
}
|
||
if (!context.mounted) {
|
||
return;
|
||
}
|
||
final profileManager = Provider.of<SocialChatUserProfileManager>(
|
||
context,
|
||
listen: false,
|
||
);
|
||
final success = await profileManager.cpRlationshipProcessApply(
|
||
context,
|
||
id,
|
||
true,
|
||
);
|
||
if (success && context.mounted) {
|
||
SmartDialog.dismiss(tag: RoomCpInviteDialog.dialogTag);
|
||
unawaited(profileManager.refreshLoadedCpProfiles());
|
||
}
|
||
}
|
||
|
||
Future<void> _rejectCpInviteDirect(
|
||
String id,
|
||
SCSystemInvitMessageRes? cpInvite,
|
||
Map<String, dynamic>? cpData,
|
||
) async {
|
||
if (!await _shouldProcessCpInvite(id, cpInvite, cpData)) {
|
||
return;
|
||
}
|
||
if (!context.mounted) {
|
||
return;
|
||
}
|
||
final profileManager = Provider.of<SocialChatUserProfileManager>(
|
||
context,
|
||
listen: false,
|
||
);
|
||
final success = await profileManager.cpRlationshipProcessApply(
|
||
context,
|
||
id,
|
||
false,
|
||
);
|
||
if (success && context.mounted) {
|
||
SmartDialog.dismiss(tag: RoomCpInviteDialog.dialogTag);
|
||
unawaited(profileManager.refreshLoadedCpProfiles());
|
||
}
|
||
}
|
||
|
||
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) {
|
||
unawaited(_acceptCpInviteDirect(id, cpInvite, cpData));
|
||
return;
|
||
}
|
||
SmartDialog.show(
|
||
tag: "showConfirmDialog",
|
||
alignment: Alignment.center,
|
||
debounce: true,
|
||
animationType: SmartAnimationType.fade,
|
||
builder: (_) {
|
||
return MsgDialog(
|
||
title: SCAppLocalizations.of(context)!.tips,
|
||
msg: SCAppLocalizations.of(context)!.confirmAcceptTheInvitation,
|
||
btnText: SCAppLocalizations.of(context)!.confirm,
|
||
onEnsure: () async {
|
||
if (type == SCSysytemMessageType.AGENT_SEND_INVITE_HOST.name) {
|
||
Provider.of<SocialChatUserProfileManager>(
|
||
context,
|
||
listen: false,
|
||
).inviteHostOpt(context, id, "1");
|
||
} else if (type == SCSysytemMessageType.BD_SEND_INVITE_AGENT.name) {
|
||
Provider.of<SocialChatUserProfileManager>(
|
||
context,
|
||
listen: false,
|
||
).inviteAgentOpt(context, id, "1");
|
||
} else if (type == SCSysytemMessageType.BD_LEADER_INVITE_BD.name) {
|
||
Provider.of<SocialChatUserProfileManager>(
|
||
context,
|
||
listen: false,
|
||
).inviteBDOpt(context, id, "1");
|
||
} else if (type ==
|
||
SCSysytemMessageType.BD_LEADER_INVITE_BD_LEADER.name) {
|
||
Provider.of<SocialChatUserProfileManager>(
|
||
context,
|
||
listen: false,
|
||
).inviteBDLeader(context, id, "1");
|
||
} else if (type ==
|
||
SCSysytemMessageType.ADMIN_INVITE_RECHARGE_AGENT.name) {
|
||
Provider.of<SocialChatUserProfileManager>(
|
||
context,
|
||
listen: false,
|
||
).inviteRechargeAgent(context, id, "1");
|
||
}
|
||
},
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
void rejectOpt(
|
||
String id,
|
||
String type, {
|
||
SCSystemInvitMessageRes? cpInvite,
|
||
Map<String, dynamic>? cpData,
|
||
}) {
|
||
if (type == SCSysytemMessageType.CP_BUILD.name) {
|
||
unawaited(_rejectCpInviteDirect(id, cpInvite, cpData));
|
||
return;
|
||
}
|
||
SmartDialog.show(
|
||
tag: "showConfirmDialog",
|
||
alignment: Alignment.center,
|
||
debounce: true,
|
||
animationType: SmartAnimationType.fade,
|
||
builder: (_) {
|
||
return MsgDialog(
|
||
title: SCAppLocalizations.of(context)!.tips,
|
||
msg: SCAppLocalizations.of(context)!.confirmDeclineTheInvitation,
|
||
btnText: SCAppLocalizations.of(context)!.confirm,
|
||
onEnsure: () async {
|
||
if (type == SCSysytemMessageType.AGENT_SEND_INVITE_HOST.name) {
|
||
Provider.of<SocialChatUserProfileManager>(
|
||
context,
|
||
listen: false,
|
||
).inviteHostOpt(context, id, "2");
|
||
} else if (type == SCSysytemMessageType.BD_SEND_INVITE_AGENT.name) {
|
||
Provider.of<SocialChatUserProfileManager>(
|
||
context,
|
||
listen: false,
|
||
).inviteAgentOpt(context, id, "2");
|
||
} else if (type == SCSysytemMessageType.BD_LEADER_INVITE_BD.name) {
|
||
Provider.of<SocialChatUserProfileManager>(
|
||
context,
|
||
listen: false,
|
||
).inviteBDOpt(context, id, "2");
|
||
} else if (type ==
|
||
SCSysytemMessageType.BD_LEADER_INVITE_BD_LEADER.name) {
|
||
Provider.of<SocialChatUserProfileManager>(
|
||
context,
|
||
listen: false,
|
||
).inviteBDLeader(context, id, "2");
|
||
} else if (type ==
|
||
SCSysytemMessageType.ADMIN_INVITE_RECHARGE_AGENT.name) {
|
||
Provider.of<SocialChatUserProfileManager>(
|
||
context,
|
||
listen: false,
|
||
).inviteRechargeAgent(context, id, "2");
|
||
}
|
||
},
|
||
);
|
||
},
|
||
);
|
||
}
|
||
}
|