aslan-flutter/lib/chatvibe_features/chat/message_chat_page.dart
2026-07-01 18:25:58 +08:00

2471 lines
94 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:convert';
import 'dart:io';
import 'package:extended_image/extended_image.dart'
show ExtendedImage, ExtendedRawImage, ExtendedImageState, LoadState;
import 'package:extended_text/extended_text.dart';
import 'package:extended_text_field/extended_text_field.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:aslan/app_localizations.dart';
import 'package:aslan/chatvibe_ui/components/at_debounce_widget.dart';
import 'package:aslan/chatvibe_ui/components/text/at_text.dart';
import 'package:aslan/chatvibe_ui/components/at_tts.dart';
import 'package:aslan/chatvibe_core/constants/at_emoji_datas.dart';
import 'package:aslan/chatvibe_core/utilities/at_date_utils.dart';
import 'package:aslan/chatvibe_core/utilities/at_loading_manager.dart';
import 'package:aslan/chatvibe_core/utilities/at_message_utils.dart';
import 'package:aslan/chatvibe_data/sources/repositories/user_repository_impl.dart';
import 'package:aslan/chatvibe_domain/models/res/login_res.dart';
import 'package:aslan/chatvibe_managers/rtm_manager.dart';
import 'package:marquee/marquee.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:tencent_cloud_chat_sdk/enum/V2TimAdvancedMsgListener.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_elem.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_image_elem.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message_extension.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message_online_url.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/models/v2_tim_video_elem.dart';
import 'package:tencent_cloud_chat_sdk/tencent_im_sdk_plugin.dart';
import 'package:aslan/config/pickImage.dart';
import 'package:aslan/chatvibe_ui/components/dialog/dialog_base.dart';
import 'package:aslan/chatvibe_ui/components/at_compontent.dart';
import 'package:aslan/chatvibe_ui/theme/chatvibe_theme.dart';
import 'package:aslan/chatvibe_core/constants/at_global_config.dart';
import 'package:aslan/chatvibe_core/config/business_logic_strategy.dart';
import 'package:aslan/chatvibe_core/constants/at_screen.dart';
import 'package:aslan/chatvibe_core/routes/at_fluro_navigator.dart';
import 'package:aslan/chatvibe_core/utilities/at_keybord_util.dart';
import 'package:aslan/chatvibe_core/utilities/at_message_notifier.dart';
import 'package:aslan/chatvibe_core/utilities/at_path_utils.dart';
import 'package:aslan/chatvibe_data/sources/local/user_manager.dart';
import 'package:aslan/chatvibe_domain/usecases/custom_tab_selector.dart';
import 'package:aslan/chatvibe_managers/user_profile_manager.dart';
import 'package:aslan/chatvibe_features/index/main_route.dart';
import '../../chatvibe_domain/models/res/at_user_red_packet_send_res.dart';
class ATMessageChatPage extends StatefulWidget {
final V2TimConversation? conversation;
final bool shrinkWrap;
//是否是房间内聊天界面。
final bool inRoom;
const ATMessageChatPage({
Key? key,
this.conversation,
this.shrinkWrap = false,
this.inRoom = false,
}) : super(key: key);
@override
_ATMessageChatPageState createState() => _ATMessageChatPageState();
}
class _ATMessageChatPageState extends State<ATMessageChatPage> {
BusinessLogicStrategy get _strategy => ATGlobalConfig.businessLogicStrategy;
final TextEditingController _textController = TextEditingController();
final ScrollController _scrollController = ScrollController();
final RefreshController _refreshController = RefreshController();
// FlutterSoundPlayer? flutterSound;
RtmProvider? rtmProvider;
V2TimConversation? currentConversation;
List<V2TimMessage> currentConversationMessageList = [];
final FocusNode _focusNode = FocusNode();
///是否显示工具栏
bool showTools = false;
bool showEmoji = false;
bool showDoNotClickUnfamiliarTips = true;
///互相关注才能互相发送消息
bool canSendMsg = false;
ChatVibeUserProfile? friend;
///是否显示发送按钮
bool showSend = false;
List<String> coinsTitles = ["100", "1000", "10000", "50000"];
String selecteCoins = "100";
@override
void initState() {
super.initState();
ATMessageNotifier.canPlay = false;
ATMessageUtils.redPacketFutureCache.clear();
// flutterSound = FlutterSoundPlayer();
rtmProvider = Provider.of<RtmProvider>(context, listen: false);
currentConversation = widget.conversation;
rtmProvider?.onMessageRecvC2CReadListener = _onMessageRecvC2CRead;
rtmProvider?.onRevokeMessageListener = _onRevokeMessage;
rtmProvider?.onNewMessageCurrentConversationListener = _onNewMessage;
loadMsg();
if (friend == null) {
loadFriend();
}
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
setState(() {
showTools = false;
showEmoji = false;
});
}
});
}
@override
void dispose() {
rtmProvider?.onMessageRecvC2CReadListener = null;
rtmProvider?.onRevokeMessageListener = null;
rtmProvider?.onNewMessageCurrentConversationListener = null;
super.dispose();
}
@override
Widget build(BuildContext context) {
return Consumer<RtmProvider>(
builder: (_, provider, __) {
return WillPopScope(
onWillPop: () {
if (showEmoji || showTools) {
setState(() {
showEmoji = false;
showTools = false;
});
return Future.value(false);
}
ATNavigatorUtils.goBack(context);
return Future.value(true);
},
child: Stack(
children: [
if (!widget.inRoom)
// 渐变背景
Positioned(
left: 0,
right: 0,
top: 0,
child: Column(
children: [
SizedBox(
width: ScreenUtil().screenWidth,
height: ScreenUtil().screenHeight,
child: Image.asset(
_strategy.getATMessageChatPageRoomSettingBackground(),
fit: BoxFit.fill,
),
),
],
),
),
Scaffold(
//backgroundColor: widget.inRoom ? Colors.transparent: Color(0xfff8f8f8),
backgroundColor: Colors.transparent,
// appBar: _appBar(),
appBar: null,
body: SafeArea(
top: widget.shrinkWrap ? false : true,
bottom: false,
child: Column(
children: <Widget>[
Row(
children: [
!widget.inRoom
? GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.pop(context);
},
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 10.w,
vertical: 10.w,
),
child: Icon(
ATGlobalConfig.lang == "ar"
? Icons.keyboard_arrow_right
: Icons.keyboard_arrow_left,
size: 28.w,
color: Colors.black,
),
),
)
: Container(),
SizedBox(width: 5.w),
Expanded(
child: Container(
alignment: AlignmentDirectional.center,
child: chatvibeNickNameText(
friend?.userNickname ?? "",
fontSize: 14.sp,
fontWeight: FontWeight.w500,
textColor: Colors.black,
type: friend?.getVIP()?.name ?? "",
needScroll:
(friend?.userNickname?.characters.length ??
0) >
22,
),
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
ATNavigatorUtils.push(
context,
replace: true,
"${MainRoute.person}?isMe=${AccountStorage().getCurrentUser()?.userProfile?.id == friend?.id}&tageId=${friend?.id}",
);
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10.w),
child: Icon(
Icons.more_vert,
size: 22.w,
color: Colors.black,
),
),
),
],
),
Expanded(child: _msgList()),
Container(
decoration: BoxDecoration(
//color: Colors.white,
//border: Border(top: BorderSide(color: Color(0xfff1f1f1)))
),
child: SafeArea(
top: false,
child: Column(
children: <Widget>[
if (currentConversation?.conversationID !=
"administrator")
_input(),
_tools(provider),
_emoji(),
// _fahongbao(),
],
),
),
),
],
),
),
),
],
),
);
},
);
}
void loadFriend() {
ATLoadingManager.exhibitOperation();
Future.wait([
AccountRepository().loadUserInfo("${currentConversation?.userID}"),
AccountRepository().friendRelationCheck(
"${currentConversation?.userID}",
),
])
.then((result) {
ATLoadingManager.veilRoutine();
friend = result[0] as ChatVibeUserProfile;
canSendMsg = result[1] as bool;
setState(() {});
})
.catchError((e) {
ATLoadingManager.veilRoutine();
});
}
///消息列表
Widget _msgList() {
print('xiaoxiliebiao:${currentConversationMessageList.length}');
return SmartRefresher(
enablePullDown: false,
enablePullUp: true,
onLoading: () async {
print('onLoading');
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>;
print('加载前:${currentConversationMessageList.length}');
currentConversationMessageList.addAll(messages);
print('加载后:${currentConversationMessageList.length}');
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: CustomScrollView(
shrinkWrap: 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,
isSystem:
currentConversationMessageList[i].sender == "administrator",
friend: friend,
currentConversationMessageList: currentConversationMessageList,
updateCall: () {
setState(() {});
},
),
childCount: currentConversationMessageList.length,
),
),
],
),
);
}
Future<void> loadMsg() async {
// 1. 在初始化时,添加高级消息监听器
TencentImSDKPlugin.v2TIMManager.getMessageManager().addAdvancedMsgListener(
listener: V2TimAdvancedMsgListener(
// 监听消息扩展更新
onRecvMessageExtensionsChanged: (msgID, extensions) {
for (var ext in extensions) {
if (ext.extensionKey == "packetID") {
String packetID = ext.extensionValue;
ATMessageUtils.redPacketFutureCache[packetID] =
AccountRepository().userRedPacketDetail(packetID);
setState(() {});
break;
}
}
},
),
);
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);
print("messages : ${messages?.length ?? 0}");
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(() {});
}
///输入栏
Widget _input() {
return Consumer<ChatVibeUserProfileManager>(
builder:
(_, provider, __) => Container(
color: Colors.white,
height: 56.w,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(width: 15.w),
Expanded(
child: Container(
height: 34.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(52.w),
color: Color(0xffEDEDED),
),
child: Row(
children: [
Expanded(
child: ExtendedTextField(
controller: _textController,
focusNode: _focusNode,
onChanged: (s) {
setState(() {
showSend = _textController.text.isNotEmpty;
});
},
onSubmitted: (s) {
if (s.isNotEmpty) {
sendMsg(s);
showSend = false;
setState(() {});
_scrollController.jumpTo(0.0);
_textController.clear();
}
},
decoration: InputDecoration(
hintText:
ATAppLocalizations.of(
context,
)!.clickHereToStartChatting,
hintStyle: TextStyle(
color: Color(0xff999999),
fontSize: 14.sp,
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 15,
),
counterText: '',
isDense: true,
filled: false,
focusColor: Colors.transparent,
hoverColor: Colors.transparent,
border: InputBorder.none,
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
disabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
focusedErrorBorder: InputBorder.none,
),
style: TextStyle(
fontSize: ScreenUtil().setSp(14),
color: Colors.black.withOpacity(1),
),
),
),
//原来的emoji按钮
//SizedBox(width: 10.w,),
],
),
),
),
SizedBox(width: 10.w),
!showEmoji
? GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
ATKeybordUtil.conceal(context);
setState(() {
if (showTools) {
showTools = false;
}
showEmoji = !showEmoji;
});
},
child: Image.asset(
_strategy.getATMessageChatPageEmojiIcon(),
width: 24.w,
//color: Colors.black,
fit: BoxFit.fill,
),
)
: Container(),
showEmoji
? GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
ATKeybordUtil.conceal(context);
setState(() {
if (showTools) {
showTools = false;
}
showEmoji = !showEmoji;
});
},
child: Image.asset(
_strategy.getATMessageChatPageChatKeyboardIcon(),
width: 24.w,
//color: Colors.black,
fit: BoxFit.fill,
),
)
: Container(),
if (!showSend) SizedBox(width: 12.w),
if (showSend) SizedBox(width: 5.w),
Visibility(
visible: !showSend,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
ATKeybordUtil.conceal(context);
setState(() {
if (showEmoji) {
showEmoji = false;
}
showTools = !showTools;
});
},
child: Image.asset(
_strategy.getATMessageChatPageAddIcon(),
width: 24.w,
//color: Colors.black,
fit: BoxFit.fill,
),
),
),
Visibility(
visible: showSend,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () async {
_scrollController.jumpTo(0.0);
if (_textController.text.isNotEmpty) {
ATKeybordUtil.conceal(context);
sendMsg(_textController.text);
showSend = false;
setState(() {});
_textController.clear();
}
},
child: Image.asset(
_strategy.getATMessageChatPageSendMessageIcon(),
height: 22.w,
width: 32.w,
),
),
),
SizedBox(width: 15.w),
],
),
),
);
}
///发消息
sendMsg(String msg) async {
if (!canSendMsg) {
ATTts.show(ATAppLocalizations.of(context)!.canSendMsgTips);
return;
}
Provider.of<RtmProvider>(
context,
listen: false,
).sendC2CTextMsg(msg, currentConversation!);
}
///发消息
sendCustomMsg(String msg, String extension) async {
if (!canSendMsg) {
ATTts.show(ATAppLocalizations.of(context)!.canSendMsgTips);
return;
}
Provider.of<RtmProvider>(
context,
listen: false,
).sendC2CCustomMsg(msg, currentConversation!, extension);
}
///工具栏
Widget _tools(RtmProvider provider) {
return Visibility(
visible: showTools,
child: Container(
color: Colors.white,
padding: EdgeInsets.only(bottom: 18.w, top: 5.w),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
SizedBox(width: 20.w),
Expanded(
child: _toolsItem(
_strategy.getATMessageChatPageCameraIcon(),
ATAppLocalizations.of(context)!.camera,
() async {
if (!canSendMsg) {
ATTts.show(ATAppLocalizations.of(context)!.canSendMsgTips);
return;
}
var pick = await ImagePick.pickFromCamera(context);
if (pick != null) {
provider.sendImageMsg(
file: pick,
conversation: currentConversation!,
);
}
},
),
),
Expanded(
child: _toolsItem(
_strategy.getATMessageChatPagePictureIcon(),
ATAppLocalizations.of(context)!.album,
() async {
if (!canSendMsg) {
ATTts.show(ATAppLocalizations.of(context)!.canSendMsgTips);
return;
}
final List<File>? result =
await ImagePick.pickPicAndVideoFromGallery(context);
if (result == null) return; // 用户取消选择
if (result.isNotEmpty) {
provider.sendImageMsg(
selectedList: result,
conversation: currentConversation!,
);
}
},
),
),
Expanded(flex: 1, child: SizedBox()),
Expanded(flex: 1, child: SizedBox()),
],
),
),
);
}
_emoji() {
return Visibility(
visible: showEmoji,
child: Container(
color: Colors.white,
height: 150.w,
child: GridView.builder(
padding: EdgeInsets.symmetric(horizontal: 15.w),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 8,
crossAxisSpacing: 8.w,
mainAxisSpacing: 8.w,
),
itemBuilder: (c, index) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
var text = ATEmojiDatas.smileys[index];
final TextEditingValue value = _textController.value;
_textController.value = value.copyWith(
text: value.text + text,
selection: TextSelection.fromPosition(
TextPosition(offset: text.length),
),
);
showSend = true;
setState(() {});
},
child: Padding(
padding: EdgeInsets.all(4.0.w),
child: ExtendedText(
ATEmojiDatas.smileys[index],
// specialTextSpanBuilder: MySpecialTextSpanBuilder(),
style: TextStyle(fontSize: sp(15)),
),
),
);
},
itemCount: ATEmojiDatas.smileys.length,
),
),
);
}
///工具项
_toolsItem(String image, String title, Function() onclick) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: onclick,
child: Column(
children: [
Image.asset(image, width: 50.w, fit: BoxFit.fitWidth),
SizedBox(height: 9.w),
Text(title, style: TextStyle(fontSize: 11.sp, color: Colors.black)),
],
),
);
}
_onRevokeMessage(String msgId) {
int index = 0;
for (var msg in currentConversationMessageList) {
if (msgId == msg.msgID) {
break;
}
index = index + 1;
}
currentConversationMessageList.removeAt(index);
setState(() {});
}
_onMessageRecvC2CRead(List<String> messageIDList) {
for (var msg in currentConversationMessageList) {
for (var id in messageIDList) {
if (id == msg.msgID) {
msg.isPeerRead = true;
}
}
}
setState(() {});
}
_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);
}
await TencentImSDKPlugin.v2TIMManager
.getMessageManager()
.markC2CMessageAsRead(userID: currentConversation!.userID!);
//发送已读回执
await TencentImSDKPlugin.v2TIMManager
.getMessageManager()
.sendMessageReadReceipts(messageIDList: [message.msgID!]);
setState(() {});
// await FTIM.getContactManager().setReadMessage(currentConversation);
}
void _showSendHongbaoDialog() {
SmartDialog.show(
tag: "showSendHongbaoDialog",
alignment: Alignment.bottomCenter,
animationType: SmartAnimationType.fade,
builder: (_) {
return SafeArea(
top: false,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 15.w),
height: 350.w,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
_strategy.getATMessageChatPageRedEnvelopeMessageBackground(),
),
fit: BoxFit.fill,
),
),
child: Column(
children: [
SizedBox(height: 120.w),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
text(
ATAppLocalizations.of(context)!.redEnvelopeTips1,
maxLines: 2,
textColor: Colors.white,
fontSize: 15.sp,
),
],
),
SizedBox(height: 10.w),
CustomTabSelector(
options: coinsTitles,
initialIndex: 0,
onChanged: (index) {
selecteCoins = coinsTitles[index];
},
),
SizedBox(height: 10.w),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: text(
ATAppLocalizations.of(context)!.msgSendRedEnvelopeTips,
maxLines: 4,
textColor: Colors.white,
fontSize: 13.sp,
),
),
],
),
Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
child: Container(
alignment: Alignment.center,
width: 135.w,
height: 38.w,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
_strategy
.getATMessageChatPageRedEnvelopeConfigTabButtonIcon(),
),
fit: BoxFit.fill,
),
),
child: text(
ATAppLocalizations.of(context)!.send,
fontSize: 16.sp,
fontWeight: FontWeight.w600,
),
),
onTap: () {
SmartDialog.dismiss(tag: "showConfirmDialog");
SmartDialog.show(
tag: "showConfirmDialog",
alignment: Alignment.center,
animationType: SmartAnimationType.fade,
builder: (_) {
return MsgDialog(
title: ATAppLocalizations.of(context)!.tips,
msg:
ATAppLocalizations.of(
context,
)!.sendRedPackConfirmTips,
btnText: ATAppLocalizations.of(context)!.confirm,
onEnsure: () {
SmartDialog.dismiss(
tag: "showSendHongbaoDialog",
);
ATLoadingManager.exhibitOperation();
AccountRepository()
.userRedPacketSend(
friend?.id ?? "",
selecteCoins,
)
.then((res) {
ATLoadingManager.veilRoutine();
sendCustomMsg(
jsonEncode(res.toJson()),
"Red_Envelopes",
);
})
.catchError((e) {
ATLoadingManager.veilRoutine();
});
},
);
},
);
},
),
],
),
SizedBox(height: 20.w),
],
),
),
);
},
);
}
}
class _MessageItem extends StatelessWidget {
final V2TimMessage message;
final V2TimMessage? preMessage;
BusinessLogicStrategy get _strategy => ATGlobalConfig.businessLogicStrategy;
// final FTIMUserProfile userProfile;
final ChatVibeUserProfile? friend;
bool isSystem = false;
List<V2TimMessage> currentConversationMessageList = [];
Function updateCall;
///上一条
late BuildContext context;
_MessageItem({
required this.message,
this.preMessage,
// this.userProfile,
this.isSystem = false,
required this.currentConversationMessageList,
this.friend,
required this.updateCall,
});
@override
Widget build(BuildContext context) {
this.context = context;
ChatVibeUserProfile? me = AccountStorage().getCurrentUser()?.userProfile;
bool showTime = true;
int timestamp = (message.timestamp ?? 0) * 1000;
int preTimestamp = (preMessage?.timestamp ?? 0) * 1000;
if (preMessage != null) {
///5分钟以内 不显示
// print('timestamp:$timestamp===preTimestamp:${preTimestamp}');
if (DateTime.fromMillisecondsSinceEpoch(timestamp)
.difference(DateTime.fromMillisecondsSinceEpoch(preTimestamp))
.inMilliseconds <
1000 * 60 * 5) {
showTime = false;
}
}
String time = ATMDateUtils.formatMessageTime(
context,
DateTime.fromMillisecondsSinceEpoch(timestamp ?? 0),
);
if (message.status == MessageStatus.V2TIM_MSG_STATUS_LOCAL_REVOKED) {
return Container(
alignment: AlignmentDirectional.center,
padding: EdgeInsets.symmetric(horizontal: 5.w, vertical: 5.w),
child: text(
ATAppLocalizations.of(context)!.messageHasBeenRecalled,
fontSize: 12.sp,
textColor: Colors.black38,
fontWeight: FontWeight.w400,
),
);
}
return Container(
margin: EdgeInsets.symmetric(horizontal: 15.w, vertical: 8.w),
child: Column(
crossAxisAlignment:
!message.isSelf!
? CrossAxisAlignment.start
: CrossAxisAlignment.end,
// 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: Color(0xFFEAEFF7),
borderRadius: BorderRadius.all(
Radius.circular(height(13)),
),
),
child: Text(
time,
style: TextStyle(
fontSize: sp(12),
color: Colors.black38,
fontWeight: FontWeight.w400,
decoration: TextDecoration.none,
height: 1,
),
),
),
Spacer(),
],
),
),
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
textDirection:
message.isSelf! ? TextDirection.rtl : TextDirection.ltr,
children: <Widget>[
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
if (isSystem) {
return;
}
ATNavigatorUtils.push(
context,
replace:
AccountStorage().getCurrentUser()?.userProfile?.id !=
message.sender,
"${MainRoute.person}?isMe=${AccountStorage().getCurrentUser()?.userProfile?.id == message.sender}&tageId=${message.sender}",
);
},
child:
message.sender == "administrator" ||
message.sender == "customer"
? ExtendedImage.asset(
_strategy.getATMessageChatPageSystemHeadImage(),
width: 45.w,
shape: BoxShape.circle,
fit: BoxFit.cover,
)
: netImage(
url:
message.isSelf!
? (me?.userAvatar ?? "")
: (friend?.userAvatar ?? ""),
shape: BoxShape.circle,
width: width(45),
),
),
// 他人消息的阴影间隔是10dp
Container(width: 8.w),
Row(
textDirection:
message.isSelf! ? TextDirection.rtl : TextDirection.ltr,
children: <Widget>[
Container(
alignment:
message.isSelf!
? AlignmentDirectional.topEnd
: AlignmentDirectional.topStart,
margin: EdgeInsets.only(top: 4.w),
child: _msg(),
),
SizedBox(width: 6.w),
Visibility(
visible:
message.status ==
MessageStatus.V2TIM_MSG_STATUS_SENDING,
child: CupertinoActivityIndicator(),
),
message.customElem?.extension == "Red_Envelopes"
? Container()
: (message.isSelf!
? (message.status ==
MessageStatus.V2TIM_MSG_STATUS_SEND_SUCC
? (message.isPeerRead!
? Text(
ATAppLocalizations.of(context)!.read,
style: TextStyle(
fontSize: sp(12),
color: Colors.grey,
decoration: TextDecoration.none,
height: 1,
),
)
: Text(
ATAppLocalizations.of(context)!.unread,
style: TextStyle(
fontSize: sp(12),
color: Colors.grey,
decoration: TextDecoration.none,
height: 1,
),
))
: Container())
: Container()),
Visibility(
visible:
message.status ==
MessageStatus.V2TIM_MSG_STATUS_SEND_FAIL,
child: Icon(Icons.error, color: Colors.red),
),
],
),
Spacer(),
],
),
],
),
);
}
_msg() {
V2TIMElem? elem = message.textElem;
if (message.elemType == MessageElemType.V2TIM_ELEM_TYPE_TEXT) {
V2TimTextElem textElem = elem as V2TimTextElem;
String content = textElem.text ?? "";
} else if (message.elemType == MessageElemType.V2TIM_ELEM_TYPE_IMAGE) {
V2TimImageElem imageElem = message.imageElem as V2TimImageElem;
var image;
if (imageElem.path!.length > 2 &&
File("${imageElem.path}").existsSync()) {
image = Image.file(File(imageElem.path!), fit: BoxFit.cover);
} else {
image = ExtendedImage.network(
'${imageElem.imageList![1]?.url}',
fit: BoxFit.cover,
width: double.infinity,
cache: true,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(Radius.circular(width(6))),
loadStateChanged: (ExtendedImageState state) {
if (state.extendedImageLoadState == LoadState.completed) {
return ExtendedRawImage(
image: state.extendedImageInfo?.image,
fit: BoxFit.cover,
);
} else {
return Image.asset(
_strategy.getATMessageChatPageLoadingIcon(),
fit: BoxFit.cover,
);
}
},
);
}
return Builder(
builder: (ct) {
return GestureDetector(
onTap: () {
List<String> ims = [];
int initialIndex = 0;
int index = 0;
for (var imageMsg in currentConversationMessageList) {
if (imageMsg.elemType ==
MessageElemType.V2TIM_ELEM_TYPE_IMAGE) {
String path = imageMsg.imageElem?.imageList![1]?.url ?? "";
if (path.isNotEmpty) {
ims.add(imageMsg.imageElem?.imageList![1]?.url ?? "");
if (imageMsg.msgID == message.msgID) {
initialIndex = index;
}
index = index + 1;
}
}
}
String encodedUrls = Uri.encodeComponent(jsonEncode(ims));
ATNavigatorUtils.push(
context,
"${MainRoute.imagePreview}?imageUrls=$encodedUrls&initialIndex=$initialIndex",
);
},
onLongPress: () {
_showMsgItemMenu(ct, "");
},
child: Container(
constraints: BoxConstraints(maxWidth: 200.w),
child: ClipRRect(
borderRadius: BorderRadius.circular(6.w),
child: image,
),
),
);
},
);
} else if (message.elemType == MessageElemType.V2TIM_ELEM_TYPE_VIDEO) {
V2TimVideoElem videoElem = message.videoElem as V2TimVideoElem;
if (videoElem.snapshotPath != null &&
videoElem.snapshotPath!.isNotEmpty) {
return Builder(
builder: (ct) {
return GestureDetector(
child: Container(
constraints: BoxConstraints(maxWidth: 200.w),
child: ClipRRect(
borderRadius: BorderRadius.circular(6.w),
child: Stack(
alignment: Alignment.center,
children: [
Image.file(
File(videoElem.snapshotPath!),
fit: BoxFit.cover,
),
Icon(Icons.play_circle, color: Colors.white, size: 55.w),
],
),
),
),
onTap: () {
String encodedVideoUrl = Uri.encodeComponent(
videoElem.videoPath ?? "",
);
ATNavigatorUtils.push(
context,
"${MainRoute.videoPlayer}?videoUrl=$encodedVideoUrl",
);
},
onLongPress: () {
_showMsgItemMenu(ct, "");
},
);
},
);
} else {
return FutureBuilder<V2TimValueCallback<V2TimMessageOnlineUrl>>(
// 假设 getMessageOnlineUrlForMessage 是对 TencentImSDKPlugin.v2TIMManager.getMessageManager().getMessageOnlineUrl 的封装,返回 Future<String>
future: ATMessageUtils().getMessageOnlineUrl(
msgID: message.msgID ?? "",
),
builder: (context, snapshot) {
// 根据异步任务状态构建UI
if (snapshot.connectionState == ConnectionState.waiting) {
// 数据加载中,显示占位符
return Container();
} else if (snapshot.hasError) {
// 数据加载失败显示错误UI
return Container();
} else if (snapshot.hasData) {
// 数据加载成功更新消息的mediaUrl并构建正常消息UI
message.videoElem = snapshot.data?.data?.videoElem!;
return Builder(
builder: (ct) {
return GestureDetector(
child: Container(
constraints: BoxConstraints(maxWidth: 200.w),
child: ClipRRect(
borderRadius: BorderRadius.circular(6.w),
child: Stack(
alignment: Alignment.center,
children: [
ATPathUtils.collectPathType(
message.videoElem?.snapshotPath ?? "",
) ==
PathType.file
? Image.file(
File(message.videoElem?.snapshotPath ?? ""),
fit: BoxFit.cover,
)
: netImage(
url: message.videoElem?.snapshotUrl ?? "",
),
Icon(
Icons.play_circle,
color: Colors.white,
size: 55.w,
),
],
),
),
),
onTap: () {
String encodedVideoUrl = Uri.encodeComponent(
message.videoElem?.videoUrl ?? "",
);
ATNavigatorUtils.push(
context,
"${MainRoute.videoPlayer}?videoUrl=$encodedVideoUrl",
);
},
onLongPress: () {
_showMsgItemMenu(ct, "");
},
);
},
);
} else {
// 其他情况
return Container();
}
},
);
}
}
return _text();
}
///文本消息
_text() {
String content = "";
if (message.elemType == MessageElemType.V2TIM_ELEM_TYPE_TEXT) {
V2TimTextElem textElem = message.textElem!;
content = textElem.text ?? "";
if (isSystem) {}
} else if (message.elemType == MessageElemType.V2TIM_ELEM_TYPE_IMAGE) {
content = ATAppLocalizations.of(context)!.image;
} else if (message.elemType == MessageElemType.V2TIM_ELEM_TYPE_VIDEO) {
content = ATAppLocalizations.of(context)!.video;
} else if (message.elemType == MessageElemType.V2TIM_ELEM_TYPE_SOUND) {
content = ATAppLocalizations.of(context)!.sound;
} else if (message.elemType == MessageElemType.V2TIM_ELEM_TYPE_CUSTOM) {
V2TimCustomElem customElem = message.customElem!;
content = customElem.data ?? "";
if (customElem.extension == 'Red_Envelopes') {
ATUserRedPacketSendRes redPacketSendRes = ATUserRedPacketSendRes.fromJson(
jsonDecode(content),
);
String packetId = redPacketSendRes.packetId ?? "";
// 获取或创建缓存 Future
Future<ATUserRedPacketSendRes> getRedPacketFuture() {
if (!ATMessageUtils.redPacketFutureCache.containsKey(packetId)) {
ATMessageUtils.redPacketFutureCache[packetId] = AccountRepository()
.userRedPacketDetail(packetId);
}
return ATMessageUtils.redPacketFutureCache[packetId]!;
}
return Builder(
builder: (ct) {
return FutureBuilder(
future: getRedPacketFuture(),
builder: (ct, AsyncSnapshot<ATUserRedPacketSendRes> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
ATUserRedPacketSendRes? resData = snapshot.data;
return ATDebounceWidget(
child: Column(
children: [
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
_strategy
.getATMessageChatPageRedEnvelopeMessageItemBackground(),
),
fit: BoxFit.fill,
),
),
child: Container(
alignment: Alignment.center,
width: 280.w,
height: 80.w,
child: Column(
children: [
SizedBox(height: 5.w),
Row(
children: [
SizedBox(width: 5.w),
Image.asset(
_strategy
.getATMessageChatPageRedEnvelopeReceivePackageIcon(),
width: 43.w,
),
SizedBox(width: 5.w),
ExtendedText(
ATAppLocalizations.of(
context,
)!.wishingYouHappinessEveryDay,
// specialTextSpanBuilder: MySpecialTextSpanBuilder(),
style: TextStyle(
fontSize: sp(13),
color: Colors.white,
),
),
],
),
Divider(
color: Colors.white,
thickness: 0.4,
height: 5.w,
endIndent: 10.w,
indent: 10.w,
),
Row(
children: [
SizedBox(width: 10.w),
Expanded(
child: text(
resData?.senderInfo?.nickName ?? "",
fontSize: sp(13),
textColor: Colors.white,
),
),
SizedBox(width: 10.w),
],
),
],
),
),
),
SizedBox(height: 5.w),
resData?.status == 1
? Row(
children: [
SizedBox(width: 5.w),
Image.asset(
_strategy
.getATMessageChatPageRedEnvelopeReceivePackageIcon(),
width: 23.w,
),
SizedBox(width: 5.w),
Container(
width: ScreenUtil().screenWidth * 0.6,
child: text(
maxLines: 2,
textColor: Colors.black26,
ATAppLocalizations.of(
context,
)!.unclaimedRedEnvelopes,
),
),
],
)
: Container(),
resData?.status == 1
? Container()
: Row(
children: [
SizedBox(width: 5.w),
Image.asset(
_strategy
.getATMessageChatPageRedEnvelopeReceivePackageIcon(),
width: 23.w,
),
SizedBox(width: 5.w),
resData?.status == 3
? text(
maxLines: 2,
ATAppLocalizations.of(
context,
)!.theRedEnvelopeHasExpired,
textColor: Colors.black26,
)
: _buildPackTips(resData),
],
),
],
),
onTap: () {
if (resData != null) {
if (resData.status == 3) {
//过期了
ATTts.show(
ATAppLocalizations.of(
context,
)!.theRedEnvelopeHasExpired,
);
return;
}
if ("${resData.senderInfo?.userId}" !=
AccountStorage()
.getCurrentUser()
?.userProfile
?.id) {
if (resData.status == 1) {
_showOpenDialog(resData);
} else {
_showOpenedDialog(resData);
}
} else {
_showOpenedDialog(resData);
}
}
},
);
}
}
return Column(
children: [
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
_strategy
.getATMessageChatPageRedEnvelopeMessageItemBackground(),
),
fit: BoxFit.fill,
),
),
child: Container(
alignment: Alignment.center,
width: 280.w,
height: 80.w,
child: Column(
children: [
SizedBox(height: 5.w),
Row(
children: [
SizedBox(width: 5.w),
Image.asset(
_strategy
.getATMessageChatPageRedEnvelopeReceivePackageIcon(),
width: 43.w,
),
SizedBox(width: 5.w),
],
),
Divider(
color: Colors.white,
thickness: 0.4,
height: 5.w,
endIndent: 10.w,
indent: 10.w,
),
],
),
),
),
SizedBox(height: 5.w),
],
);
},
);
},
);
} else {
content = ATAppLocalizations.of(context)!.receivedAMessage;
}
}
return Builder(
builder: (ct) {
return GestureDetector(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [BoxShadow(blurRadius: 2.w, color: Colors.black26)],
borderRadius: BorderRadius.only(
topLeft:
message.isSelf! ? Radius.circular(8) : Radius.circular(0),
topRight: Radius.circular(8.w),
bottomLeft: Radius.circular(8.w),
bottomRight:
message.isSelf! ? Radius.circular(0) : Radius.circular(8),
),
),
padding: EdgeInsets.all(8.0.w),
child: Container(
constraints: BoxConstraints(maxWidth: width(220)),
child: ExtendedText(
content,
// specialTextSpanBuilder: MySpecialTextSpanBuilder(),
style: TextStyle(
fontSize: sp(14),
color: message.isSelf! ? Colors.black87 : Colors.black87,
),
),
),
),
onLongPress: () {
_showMsgItemMenu(ct, content);
},
);
},
);
}
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(
_strategy.getATMessageChatPageMessageMenuDeleteIcon(),
width: 20.w,
),
SizedBox(height: 3.w),
text(
ATAppLocalizations.of(context)!.delete,
fontSize: 12.sp,
textColor: Color(0xff777777),
),
],
),
),
),
content.isNotEmpty
? GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
SmartDialog.dismiss(tag: "showMsgItemMenu");
Clipboard.setData(ClipboardData(text: content));
ATTts.show(
ATAppLocalizations.of(context)!.copiedToClipboard,
);
},
child: Container(
margin: EdgeInsets.symmetric(horizontal: 8.w),
child: Column(
children: [
Image.asset(
_strategy.getATMessageChatPageMessageMenuCopyIcon(),
width: 20.w,
),
SizedBox(height: 3.w),
text(
ATAppLocalizations.of(context)!.copy,
fontSize: 12.sp,
textColor: Color(0xff777777),
),
],
),
),
)
: Container(),
(message.isSelf ?? false)
? GestureDetector(
onTap: () {
SmartDialog.dismiss(tag: "showMsgItemMenu");
_revokeMessage();
},
behavior: HitTestBehavior.opaque,
child: Container(
margin: EdgeInsets.symmetric(horizontal: 8.w),
child: Column(
children: [
Image.asset(
_strategy
.getATMessageChatPageMessageMenuRecallIcon(),
width: 20.w,
),
SizedBox(height: 3.w),
text(
ATAppLocalizations.of(context)!.recall,
fontSize: 12.sp,
textColor: Color(0xff777777),
),
],
),
),
)
: Container(),
],
),
);
},
);
}
///撤回消息
void _revokeMessage() async {
SmartDialog.show(
tag: "showConfirmDialog",
alignment: Alignment.center,
debounce: true,
animationType: SmartAnimationType.fade,
builder: (_) {
return MsgDialog(
title: ATAppLocalizations.of(context)!.tips,
msg: ATAppLocalizations.of(context)!.recallThisMessage,
btnText: ATAppLocalizations.of(context)!.confirm,
onEnsure: () async {
// 撤回指定msgID的消息
V2TimCallback revokeMessage = await TencentImSDKPlugin.v2TIMManager
.getMessageManager()
.revokeMessage(msgID: message.msgID ?? "");
await TencentImSDKPlugin.v2TIMManager
.getMessageManager()
.deleteMessages(msgIDs: [message.msgID ?? ""]);
if (revokeMessage.code == 0) {
// 撤回成功
int index = 0;
for (var value in currentConversationMessageList) {
if (value.msgID == message.msgID) {
break;
}
index = index + 1;
}
currentConversationMessageList.removeAt(index);
updateCall();
} else {
// 撤回失败,可通过 revokeMessage.desc 获取错误描述
ATTts.show("fail:${revokeMessage.desc}");
}
},
);
},
);
}
///删除消息
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(
ATAppLocalizations.of(context)!.tips,
fontSize: 16.sp,
textColor: Colors.black,
fontWeight: FontWeight.bold,
),
],
),
SizedBox(height: 5.w),
Divider(height: height(1), color: ChatVibeTheme.dividerColor),
GestureDetector(
child: Container(
padding: EdgeInsets.symmetric(vertical: 10.w),
color: Colors.transparent,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
text(
ATAppLocalizations.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: ChatVibeTheme.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(
ATAppLocalizations.of(context)!.deleteOnAllDevices,
fontSize: 14.sp,
textColor: Colors.black,
),
],
),
),
),
Divider(height: height(1), color: ChatVibeTheme.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(
ATAppLocalizations.of(context)!.cancel,
fontSize: 14.sp,
textColor: Colors.black,
),
],
),
),
),
],
),
),
);
},
);
}
Future<void> updateRedPacketStatus(String messageID, String packetID) async {
// 构建扩展信息例如标记为已领取并包含领取者ID
Map<String, String> extensionMap = {"packetID": packetID};
List<V2TimMessageExtension> extensions =
extensionMap.entries
.map(
(e) => V2TimMessageExtension(
extensionKey: e.key,
extensionValue: e.value,
),
)
.toList();
await TencentImSDKPlugin.v2TIMManager
.getMessageManager()
.setMessageExtensions(
msgID: messageID, // 原始红包消息的ID
extensions: extensions,
);
}
void _showOpenDialog(ATUserRedPacketSendRes resData) {
SmartDialog.show(
tag: "showOpenDialog",
alignment: Alignment.center,
debounce: true,
animationType: SmartAnimationType.fade,
builder: (_) {
return Container(
height: 400.w,
alignment: Alignment.topCenter,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
_strategy.getATMessageChatPageRedEnvelopeOpenBackground(),
),
fit: BoxFit.fill,
),
),
child: Column(
children: [
SizedBox(height: 100.w),
ATDebounceWidget(
child: Container(
alignment: Alignment.center,
width: 60.w,
height: 60.w,
color: Colors.transparent,
child: text(
ATAppLocalizations.of(context)!.open,
textColor: Colors.white,
fontSize: 16.sp,
fontWeight: FontWeight.w900,
),
),
onTap: () {
SmartDialog.dismiss(tag: "showOpenDialog");
ATLoadingManager.exhibitOperation();
AccountRepository()
.userRedPacketGrab(resData.packetId ?? "")
.then((res) {
var future = AccountRepository().userRedPacketDetail(
resData.packetId ?? "",
);
updateRedPacketStatus(
message.msgID ?? "",
resData.packetId ?? "",
);
ATMessageUtils.redPacketFutureCache[resData.packetId ??
""] =
future;
future
.then((res2) {
ATLoadingManager.veilRoutine();
updateCall();
_showOpenedDialog(res2);
})
.catchError((e) {
ATLoadingManager.veilRoutine();
});
})
.catchError((e) {
ATLoadingManager.veilRoutine();
});
},
),
SizedBox(height: 35.w),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
text(
ATAppLocalizations.of(context)!.openRedPackDialogTip,
fontWeight: FontWeight.w600,
textColor: Colors.white,
fontSize: 14.sp,
),
SizedBox(width: 3.w),
Container(
margin: EdgeInsets.only(bottom: 1.w),
height: 18.w,
constraints: BoxConstraints(maxWidth: 65.w),
child:
(resData.senderInfo?.nickName?.length ?? 0) > 6
? Marquee(
text: resData.senderInfo?.nickName ?? "",
style: TextStyle(
fontSize: 14.sp,
color: Colors.white,
fontWeight: FontWeight.w600,
decoration: TextDecoration.none,
),
scrollAxis: Axis.horizontal,
crossAxisAlignment: CrossAxisAlignment.start,
blankSpace: 20.0,
velocity: 40.0,
pauseAfterRound: Duration(seconds: 1),
accelerationDuration: Duration(seconds: 1),
accelerationCurve: Curves.easeOut,
decelerationDuration: Duration(milliseconds: 550),
decelerationCurve: Curves.easeOut,
)
: Text(
resData.senderInfo?.nickName ?? "",
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 14.sp,
color: Colors.white,
fontWeight: FontWeight.w600,
decoration: TextDecoration.none,
),
),
),
SizedBox(width: 3.w),
Container(
child: text(
ATAppLocalizations.of(context)!.sent,
fontWeight: FontWeight.w600,
textColor: Colors.white,
fontSize: 14.sp,
),
height: 18.w,
),
],
),
SizedBox(height: 15.w),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
text(
ATAppLocalizations.of(context)!.wishingYouHappinessEveryDay,
fontWeight: FontWeight.w600,
textColor: Colors.white70,
fontSize: 13.sp,
),
],
),
],
),
);
},
);
}
void _showOpenedDialog(ATUserRedPacketSendRes resData) {
SmartDialog.show(
tag: "showOpenedDialog",
alignment: Alignment.center,
debounce: true,
animationType: SmartAnimationType.fade,
builder: (_) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 20.w),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
_strategy.getATMessageChatPageRedEnvelopeOpenedBackground(),
),
fit: BoxFit.fill,
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 70.w),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
child: Icon(Icons.close, size: 18.w, color: Colors.white),
onTap: () {
SmartDialog.dismiss(tag: "showOpenedDialog");
},
),
SizedBox(width: 10.w),
],
),
SizedBox(height: 25.w),
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(width: 20.w),
netImage(
url: resData.senderInfo?.avatar ?? "",
shape: BoxShape.circle,
width: 45.w,
height: 45.w,
),
SizedBox(width: 10.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
height: 18.w,
constraints: BoxConstraints(maxWidth: 85.w),
child:
(resData.senderInfo?.nickName?.length ?? 0) > 8
? Marquee(
text: resData.senderInfo?.nickName ?? "",
style: TextStyle(
fontSize: 14.sp,
color: Colors.white,
fontWeight: FontWeight.w600,
decoration: TextDecoration.none,
),
scrollAxis: Axis.horizontal,
crossAxisAlignment:
CrossAxisAlignment.start,
blankSpace: 20.0,
velocity: 40.0,
pauseAfterRound: Duration(seconds: 1),
accelerationDuration: Duration(
seconds: 1,
),
accelerationCurve: Curves.easeOut,
decelerationDuration: Duration(
milliseconds: 500,
),
decelerationCurve: Curves.easeOut,
)
: Text(
resData.senderInfo?.nickName ?? "",
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 14.sp,
color: Colors.white,
fontWeight: FontWeight.w600,
decoration: TextDecoration.none,
),
),
),
SizedBox(width: 5.w),
Container(
child: text(
ATAppLocalizations.of(context)!.sentARedEnvelope,
fontWeight: FontWeight.w600,
textColor: Colors.white,
fontSize: 14.sp,
),
height: 18.w,
),
],
),
SizedBox(height: 5.w),
Row(
children: [
text(
ATAppLocalizations.of(
context,
)!.wishingYouHappinessEveryDay,
fontWeight: FontWeight.w600,
textColor: Colors.white70,
fontSize: 13.sp,
),
],
),
],
),
],
),
SizedBox(height: 10.w),
AccountStorage().getCurrentUser()?.userProfile?.id ==
"${resData.receiverInfo?.userId}"
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
_strategy.getATMessageChatPageGoldCoinIcon(),
height: 35.w,
),
text(
"${resData.totalAmount ?? 0}",
fontWeight: FontWeight.w900,
textColor: Color(0xffFFF836),
fontSize: 22.sp,
),
],
)
: Container(),
Divider(
color: Color(0xffF3F3F3),
endIndent: 15.w,
indent: 15.w,
thickness: 0.4,
),
SizedBox(height: 5.w),
Row(
children: [
SizedBox(width: 15.w),
text(
ATAppLocalizations.of(
context,
)!.redEnvelopeAmount("${resData.totalAmount}"),
fontWeight: FontWeight.w600,
textColor: Colors.white70,
fontSize: 13.sp,
),
Spacer(),
resData.status == 2
? Row(
children: [
Image.asset(
_strategy.getATMessageChatPageGoldCoinIcon(),
height: 15.w,
),
text(
"${resData.totalAmount ?? 0}",
fontWeight: FontWeight.w400,
textColor: Color(0xffFFF836),
fontSize: 14.sp,
),
],
)
: Container(),
SizedBox(width: 15.w),
],
),
SizedBox(height: 8.w),
resData.status == 2
? Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(width: 20.w),
netImage(
url: resData.receiverInfo?.avatar ?? "",
shape: BoxShape.circle,
width: 45.w,
height: 45.w,
),
SizedBox(width: 10.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
height: 18.w,
constraints: BoxConstraints(maxWidth: 120.w),
child:
(resData.receiverInfo?.nickName?.length ??
0) >
12
? Marquee(
text:
resData.receiverInfo?.nickName ??
"",
style: TextStyle(
fontSize: 14.sp,
color: Colors.white,
fontWeight: FontWeight.w600,
decoration: TextDecoration.none,
),
scrollAxis: Axis.horizontal,
crossAxisAlignment:
CrossAxisAlignment.start,
blankSpace: 20.0,
velocity: 40.0,
pauseAfterRound: Duration(seconds: 1),
accelerationDuration: Duration(
seconds: 1,
),
accelerationCurve: Curves.easeOut,
decelerationDuration: Duration(
milliseconds: 500,
),
decelerationCurve: Curves.easeOut,
)
: Text(
resData.receiverInfo?.nickName ?? "",
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 14.sp,
color: Colors.white,
fontWeight: FontWeight.w600,
decoration: TextDecoration.none,
),
),
),
SizedBox(width: 5.w),
],
),
SizedBox(height: 5.w),
Row(
children: [
text(
ATMDateUtils.formatDateTime3(
DateTime.fromMillisecondsSinceEpoch(
resData.grabbedAt ?? 0,
),
),
fontWeight: FontWeight.w600,
textColor: Colors.white70,
fontSize: 13.sp,
),
],
),
],
),
],
)
: (resData.status == 1
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
text(
ATAppLocalizations.of(
context,
)!.redEnvelopeNotYetClaimed,
fontWeight: FontWeight.w600,
textColor: Colors.white,
fontSize: 15.sp,
),
],
)
: Container()),
SizedBox(height: 18.w),
],
),
);
},
);
}
_buildPackTips(ATUserRedPacketSendRes? resData) {
//状态1-待领取 2-已领取 3-已过期
if (resData?.status == 2) {
if ("${resData?.receiverInfo?.userId}" ==
AccountStorage().getCurrentUser()?.userProfile?.id) {
return Container(
width: ScreenUtil().screenWidth * 0.6,
child: Text.rich(
TextSpan(
children: [
TextSpan(
text: ATAppLocalizations.of(
context,
)!.youAccepted(resData?.senderInfo?.nickName ?? ""),
style: TextStyle(
fontSize: 12.sp,
color: Colors.black26,
fontWeight: FontWeight.bold,
),
),
TextSpan(
text: ATAppLocalizations.of(context)!.redEnvelope,
style: TextStyle(
fontSize: 12.sp,
color: Color(0xffFF7759),
fontWeight: FontWeight.w600,
),
),
TextSpan(
text: ".",
style: TextStyle(
fontSize: 12.sp,
color: Color(0xffFF7759),
fontWeight: FontWeight.bold,
),
),
],
),
),
);
} else if ("${resData?.senderInfo?.userId}" ==
AccountStorage().getCurrentUser()?.userProfile?.id) {
return Container(
width: ScreenUtil().screenWidth * 0.6,
child: Text.rich(
TextSpan(
children: [
TextSpan(
text: ATAppLocalizations.of(
context,
)!.acceptedYour(resData?.receiverInfo?.nickName ?? ""),
style: TextStyle(
fontSize: 12.sp,
color: Colors.black26,
fontWeight: FontWeight.bold,
),
),
TextSpan(
text: ATAppLocalizations.of(context)!.redEnvelope,
style: TextStyle(
fontSize: 12.sp,
color: Color(0xffFF7759),
fontWeight: FontWeight.w600,
),
),
TextSpan(
text: ".",
style: TextStyle(
fontSize: 12.sp,
color: Color(0xffFF7759),
fontWeight: FontWeight.bold,
),
),
],
),
),
);
}
}
return Container();
}
}
// class MySpecialTextSpanBuilder extends SpecialTextSpanBuilder {
// /// whether show background for @somebody
// MySpecialTextSpanBuilder();
//
// @override
// TextSpan build(String data, {TextStyle? textStyle, onTap}) {
// var textSpan = super.build(data, textStyle: textStyle, onTap: onTap);
// return textSpan;
// }
//
// @override
// SpecialText? createSpecialText(
// String flag, {
// TextStyle? textStyle,
// SpecialTextGestureTapCallback? onTap,
// required int index,
// }) {
// if (flag == null || flag == "") return null;
//
// ///index is end index of start flag, so text start index should be index-(flag.length-1)
// if (textStyle != null) {
// if (isStart(flag, EmojiText.flag)) {
// return EmojiText(textStyle, start: index - (EmojiText.flag.length - 1));
// }
// }
// return null;
// }
// }
// class EmojiText extends SpecialText {
// EmojiText(TextStyle textStyle, {required this.start})
// : super(EmojiText.flag, ']', textStyle);
// static const String flag = '[';
// final int start;
//
// @override
// InlineSpan finishText() {
// String key = toString();
// key = key.replaceAll("[", "");
// key = key.replaceAll("]", "");
// int index;
// try {
// index = int.parse(key);
// } catch (e) {
// return TextSpan(text: toString(), style: textStyle);
// }
//
// ///https://github.com/flutter/flutter/issues/42086
// /// widget span is not working on web
// if (index <= 113) {
// //fontsize id define image height
// //size = 30.0/26.0 * fontSize
// double size = 16.w;
//
// ///fontSize 26 and text height =30.0
// //final double fontSize = 26.0;
// return ImageSpan(
// AssetImage("atu_images/msg/emoji/$key.png"),
// actualText: key,
// imageWidth: textStyle!.fontSize!,
// imageHeight: textStyle!.fontSize!,
// start: start,
// fit: BoxFit.fill,
// margin: const EdgeInsets.only(left: 2.0, top: 2.0, right: 2.0),
// );
// }
//
// return TextSpan(text: toString(), style: textStyle);
// }
// }