mirror of
https://github.com/WuKongIM/WuKongIMFlutterSDK
synced 2025-05-24 11:22:20 +00:00
582 lines
20 KiB
Dart
582 lines
20 KiB
Dart
import 'package:example/const.dart';
|
||
import 'package:example/http.dart';
|
||
import 'package:example/order_message_content.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:wukongimfluttersdk/entity/channel.dart';
|
||
import 'package:wukongimfluttersdk/entity/msg.dart';
|
||
import 'package:wukongimfluttersdk/model/wk_text_content.dart';
|
||
import 'package:wukongimfluttersdk/proto/proto.dart';
|
||
import 'package:wukongimfluttersdk/type/const.dart';
|
||
import 'package:wukongimfluttersdk/wkim.dart';
|
||
|
||
import 'chatview.dart';
|
||
import 'msg.dart';
|
||
import 'ui_input_dialog.dart';
|
||
|
||
class ChatPage extends StatelessWidget {
|
||
const ChatPage({super.key});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final ChatChannel channel =
|
||
ModalRoute.of(context)!.settings.arguments as ChatChannel;
|
||
return MaterialApp(
|
||
theme: ThemeData(
|
||
primaryColor: Colors.redAccent,
|
||
),
|
||
home: ChatList(channel.channelID, channel.channelType),
|
||
);
|
||
}
|
||
}
|
||
|
||
class ChatList extends StatefulWidget {
|
||
String channelID;
|
||
int channelType = 0;
|
||
ChatList(this.channelID, this.channelType, {super.key});
|
||
|
||
@override
|
||
State<StatefulWidget> createState() {
|
||
return ChatListDataState(channelID, channelType);
|
||
}
|
||
}
|
||
|
||
class ChatListDataState extends State<ChatList> {
|
||
String channelID;
|
||
int channelType = 0;
|
||
final ScrollController _scrollController = ScrollController();
|
||
|
||
ChatListDataState(this.channelID, this.channelType) {
|
||
WKIM.shared.channelManager
|
||
.getChannel(channelID, channelType)
|
||
.then((channel) {
|
||
WKIM.shared.channelManager.fetchChannelInfo(channelID, channelType);
|
||
title = '${channel?.channelName}';
|
||
print("扩展:${channel?.localExtra}");
|
||
print("扩展1:${channel?.remoteExtraMap}");
|
||
});
|
||
}
|
||
List<UIMsg> msgList = [];
|
||
String title = '';
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
initListener();
|
||
getMsgList(0, 0, true);
|
||
}
|
||
|
||
initListener() {
|
||
// 监听刷新频道
|
||
WKIM.shared.channelManager.addOnRefreshListener('chat', (channel) {
|
||
if (channelID == channel.channelID) {
|
||
title = channel.channelName;
|
||
}
|
||
for (var i = 0; i < msgList.length; i++) {
|
||
if (msgList[i].wkMsg.fromUID == channel.channelID) {
|
||
msgList[i].wkMsg.setFrom(channel);
|
||
}
|
||
}
|
||
setState(() {});
|
||
});
|
||
|
||
// 监听发送消息入库返回
|
||
WKIM.shared.messageManager.addOnMsgInsertedListener((wkMsg) {
|
||
setState(() {
|
||
msgList.add(UIMsg(wkMsg));
|
||
});
|
||
Future.delayed(const Duration(milliseconds: 500), () {
|
||
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
|
||
});
|
||
});
|
||
|
||
// 监听新消息
|
||
WKIM.shared.messageManager.addOnNewMsgListener('chat', (msgs) {
|
||
print('收到${msgs.length}条新消息');
|
||
setState(() {
|
||
for (var i = 0; i < msgs.length; i++) {
|
||
if (msgs[i].channelID != channelID) {
|
||
continue;
|
||
}
|
||
if (msgs[i].setting.receipt == 1) {
|
||
// 消息需要回执
|
||
testReceipt(msgs[i]);
|
||
}
|
||
if (msgs[i].isDeleted == 0) {
|
||
msgList.add(UIMsg(msgs[i]));
|
||
}
|
||
}
|
||
});
|
||
Future.delayed(const Duration(milliseconds: 500), () {
|
||
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
|
||
});
|
||
});
|
||
|
||
// 监听消息刷新
|
||
WKIM.shared.messageManager.addOnRefreshMsgListener('chat', (wkMsg) {
|
||
for (var i = 0; i < msgList.length; i++) {
|
||
if (msgList[i].wkMsg.clientMsgNO == wkMsg.clientMsgNO) {
|
||
msgList[i].wkMsg.messageID = wkMsg.messageID;
|
||
msgList[i].wkMsg.messageSeq = wkMsg.messageSeq;
|
||
msgList[i].wkMsg.status = wkMsg.status;
|
||
msgList[i].wkMsg.wkMsgExtra = wkMsg.wkMsgExtra;
|
||
break;
|
||
}
|
||
}
|
||
setState(() {});
|
||
});
|
||
|
||
// 监听删除消息
|
||
WKIM.shared.messageManager.addOnDeleteMsgListener('chat', (clientMsgNo) {
|
||
for (var i = 0; i < msgList.length; i++) {
|
||
if (msgList[i].wkMsg.clientMsgNO == clientMsgNo) {
|
||
setState(() {
|
||
msgList.removeAt(i);
|
||
});
|
||
break;
|
||
}
|
||
}
|
||
});
|
||
|
||
// 清除聊天记录
|
||
WKIM.shared.messageManager.addOnClearChannelMsgListener("chat",
|
||
(channelId, channelType) {
|
||
if (channelID == channelId) {
|
||
msgList.clear();
|
||
setState(() {});
|
||
}
|
||
});
|
||
}
|
||
|
||
// 模拟同步消息扩展后保存到db
|
||
testReceipt(WKMsg wkMsg) async {
|
||
if (wkMsg.viewed == 0) {
|
||
var maxVersion = await WKIM.shared.messageManager
|
||
.getMaxExtraVersionWithChannel(channelID, channelType);
|
||
var extra = WKMsgExtra();
|
||
extra.messageID = wkMsg.messageID;
|
||
extra.channelID = channelID;
|
||
extra.channelType = channelType;
|
||
extra.readed = 1;
|
||
extra.readedCount = 1;
|
||
extra.extraVersion = maxVersion + 1;
|
||
List<WKMsgExtra> list = [];
|
||
list.add(extra);
|
||
WKIM.shared.messageManager.saveRemoteExtraMsg(list);
|
||
}
|
||
}
|
||
|
||
getPrevious() {
|
||
var oldOrderSeq = 0;
|
||
for (var msg in msgList) {
|
||
if (oldOrderSeq == 0 || oldOrderSeq > msg.wkMsg.orderSeq) {
|
||
oldOrderSeq = msg.wkMsg.orderSeq;
|
||
}
|
||
}
|
||
getMsgList(oldOrderSeq, 0, false);
|
||
}
|
||
|
||
getLast() {
|
||
var oldOrderSeq = 0;
|
||
for (var msg in msgList) {
|
||
if (oldOrderSeq == 0 || oldOrderSeq < msg.wkMsg.orderSeq) {
|
||
oldOrderSeq = msg.wkMsg.orderSeq;
|
||
}
|
||
}
|
||
getMsgList(oldOrderSeq, 1, false);
|
||
}
|
||
|
||
getMsgList(int oldestOrderSeq, int pullMode, bool isReset) {
|
||
WKIM.shared.messageManager.getOrSyncHistoryMessages(channelID, channelType,
|
||
oldestOrderSeq, oldestOrderSeq == 0, pullMode, 5, 0, (list) {
|
||
print('同步完成${list.length}条消息');
|
||
List<UIMsg> uiList = [];
|
||
for (int i = 0; i < list.length; i++) {
|
||
if (pullMode == 0 && !isReset) {
|
||
uiList.add(UIMsg(list[i]));
|
||
// msgList.insert(0, UIMsg(list[i]));
|
||
} else {
|
||
msgList.add(UIMsg(list[i]));
|
||
}
|
||
}
|
||
if (uiList.isNotEmpty) {
|
||
msgList.insertAll(0, uiList);
|
||
}
|
||
setState(() {});
|
||
if (isReset) {
|
||
Future.delayed(const Duration(milliseconds: 300), () {
|
||
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
|
||
});
|
||
}
|
||
}, () {
|
||
print('消息同步中');
|
||
});
|
||
}
|
||
|
||
Widget _buildRow(UIMsg uiMsg, BuildContext context) {
|
||
if (uiMsg.wkMsg.wkMsgExtra?.revoke == 1) {
|
||
return Padding(
|
||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||
child: getRevokedView(uiMsg, context),
|
||
);
|
||
}
|
||
if (uiMsg.wkMsg.fromUID == UserInfo.uid) {
|
||
return Padding(
|
||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.end,
|
||
crossAxisAlignment: CrossAxisAlignment.end,
|
||
children: [
|
||
Flexible(
|
||
child: getSendView(uiMsg, context),
|
||
),
|
||
const SizedBox(width: 8),
|
||
Padding(
|
||
padding: const EdgeInsets.only(bottom: 4),
|
||
child: chatAvatar(uiMsg),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
} else {
|
||
return Padding(
|
||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.start,
|
||
crossAxisAlignment: CrossAxisAlignment.end,
|
||
children: [
|
||
Padding(
|
||
padding: const EdgeInsets.only(bottom: 4),
|
||
child: chatAvatar(uiMsg),
|
||
),
|
||
const SizedBox(width: 8),
|
||
Flexible(
|
||
child: getRecvView(uiMsg, context),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
var content = '';
|
||
final TextEditingController _textEditingController = TextEditingController();
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(
|
||
title: Text(title),
|
||
actions: [
|
||
PopupMenuButton<String>(
|
||
onSelected: (value) => {
|
||
if (value == '清空聊天记录')
|
||
{
|
||
showDialog(
|
||
context: context,
|
||
builder: (context) {
|
||
return AlertDialog(
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(5.0),
|
||
),
|
||
backgroundColor: Colors.white,
|
||
title: const Text('确认清空聊天记录?'),
|
||
content: const Text('清空后将无法恢复,确定要清空吗?'),
|
||
actions: <Widget>[
|
||
GestureDetector(
|
||
child: const Text(
|
||
'取消',
|
||
style: TextStyle(
|
||
color: Color.fromARGB(255, 113, 112, 112),
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.bold),
|
||
),
|
||
onTap: () {
|
||
Navigator.of(context).pop();
|
||
},
|
||
),
|
||
GestureDetector(
|
||
child: Container(
|
||
margin: const EdgeInsets.only(left: 20),
|
||
child: const Text('确认',
|
||
style: TextStyle(
|
||
color: Colors.red,
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.bold)),
|
||
),
|
||
onTap: () {
|
||
Navigator.of(context).pop();
|
||
HttpUtils.clearChannelMsg(
|
||
channelID, channelType);
|
||
},
|
||
),
|
||
],
|
||
);
|
||
})
|
||
}
|
||
else if (value == '修改群名称')
|
||
{showUpdateChannelNameDialog(context)}
|
||
},
|
||
itemBuilder: (context) {
|
||
return getPopuMenuItems();
|
||
},
|
||
)
|
||
],
|
||
),
|
||
floatingActionButton: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.end,
|
||
mainAxisAlignment: MainAxisAlignment.end,
|
||
children: [
|
||
FloatingActionButton(
|
||
heroTag: 'previous',
|
||
onPressed: () {
|
||
getPrevious();
|
||
},
|
||
tooltip: '上一页',
|
||
backgroundColor: Colors.white,
|
||
child: const Icon(Icons.vertical_align_top),
|
||
),
|
||
const SizedBox(height: 10.0),
|
||
FloatingActionButton(
|
||
heroTag: 'next',
|
||
onPressed: () {
|
||
getLast();
|
||
},
|
||
backgroundColor: Colors.white,
|
||
tooltip: '下一页',
|
||
child: const Icon(Icons.vertical_align_bottom),
|
||
),
|
||
const SizedBox(height: 70.0),
|
||
]),
|
||
body: Container(
|
||
padding:
|
||
const EdgeInsets.only(left: 10, top: 10, right: 10, bottom: 10),
|
||
color: const Color.fromARGB(255, 221, 221, 221),
|
||
child: Column(
|
||
children: [
|
||
Expanded(
|
||
child: ListView.builder(
|
||
controller: _scrollController,
|
||
shrinkWrap: true,
|
||
itemCount: msgList.length,
|
||
itemBuilder: (context, pos) {
|
||
return _buildRow(msgList[pos], context);
|
||
}),
|
||
),
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: TextField(
|
||
onChanged: (v) {
|
||
content = v;
|
||
},
|
||
controller: _textEditingController,
|
||
decoration: const InputDecoration(hintText: '请输入内容'),
|
||
autofocus: true),
|
||
),
|
||
MaterialButton(
|
||
onPressed: () {
|
||
DateTime now = DateTime.now();
|
||
var orderMsg = OrderMsg();
|
||
orderMsg.title = "问界M9纯电版 旗舰SUV 2024款 3.0L 自动 豪华版";
|
||
orderMsg.num = 300;
|
||
orderMsg.price = 20;
|
||
orderMsg.orderNo = '${now.millisecondsSinceEpoch}';
|
||
orderMsg.imgUrl =
|
||
"https://img0.baidu.com/it/u=4245434814,3643211003&fm=253&fmt=auto&app=120&f=JPEG?w=674&h=500";
|
||
WKIM.shared.messageManager.sendMessage(
|
||
orderMsg, WKChannel(channelID, channelType));
|
||
},
|
||
color: Colors.brown,
|
||
child: const Text("自定义消息",
|
||
style: TextStyle(color: Colors.white)),
|
||
),
|
||
const SizedBox(width: 10.0),
|
||
MaterialButton(
|
||
onPressed: () {
|
||
if (content != '') {
|
||
_textEditingController.text = '';
|
||
Setting setting = Setting();
|
||
setting.receipt = 1; //开启回执
|
||
// 回复
|
||
WKTextContent text = WKTextContent(content);
|
||
WKReply reply = WKReply();
|
||
reply.messageId = "11";
|
||
reply.rootMid = "111";
|
||
reply.fromUID = "11";
|
||
reply.fromName = "12";
|
||
WKTextContent payloadText = WKTextContent("dds");
|
||
reply.payload = payloadText;
|
||
text.reply = reply;
|
||
// 标记
|
||
List<WKMsgEntity> list = [];
|
||
WKMsgEntity entity = WKMsgEntity();
|
||
entity.offset = 0;
|
||
entity.value = "1";
|
||
entity.length = 1;
|
||
list.add(entity);
|
||
text.entities = list;
|
||
// 艾特
|
||
WKMentionInfo mentionInfo = WKMentionInfo();
|
||
mentionInfo.mentionAll = true;
|
||
mentionInfo.uids = ['uid_1', 'uid_2'];
|
||
text.mentionInfo = mentionInfo;
|
||
// CustomMsg customMsg = CustomMsg(content);
|
||
var option = WKSendOptions();
|
||
option.setting = setting;
|
||
WKIM.shared.messageManager.sendWithOption(
|
||
text, WKChannel(channelID, channelType), option);
|
||
|
||
// WKImageContent imageContent = WKImageContent(100, 200);
|
||
// imageContent.localPath = 'addskds';
|
||
// WKIM.shared.messageManager.sendMessage(
|
||
// imageContent, WKChannel(channelID, channelType));
|
||
// WKCardContent cardContent = WKCardContent('333', '我333');
|
||
// WKIM.shared.messageManager.sendMessage(
|
||
// cardContent, WKChannel(channelID, channelType));
|
||
// WKVideoContent videoContent = WKVideoContent();
|
||
// videoContent.coverLocalPath = 'coverLocalPath';
|
||
// videoContent.localPath = 'localPath';
|
||
// videoContent.height = 10;
|
||
// videoContent.width = 100;
|
||
// videoContent.size = 122;
|
||
// videoContent.second = 9;
|
||
// WKIM.shared.messageManager.sendMessage(
|
||
// videoContent, WKChannel(channelID, channelType));
|
||
// WKVoiceContent voiceContent = WKVoiceContent(10);
|
||
// voiceContent.localPath = 'videoContent';
|
||
// voiceContent.waveform = 'waveform';
|
||
// WKIM.shared.messageManager.sendMessage(
|
||
// voiceContent, WKChannel(channelID, channelType));
|
||
}
|
||
},
|
||
color: Colors.blue,
|
||
child: const Text(
|
||
'发送',
|
||
style: TextStyle(color: Colors.white),
|
||
),
|
||
)
|
||
],
|
||
)
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
getPopuMenuItems() {
|
||
var list = <PopupMenuItem<String>>[];
|
||
list.add(const PopupMenuItem<String>(
|
||
value: '清空聊天记录',
|
||
child: Text('清空聊天记录'),
|
||
));
|
||
if (channelType == WKChannelType.group) {
|
||
list.add(const PopupMenuItem<String>(
|
||
value: '修改群名称',
|
||
child: Text('修改群名称'),
|
||
));
|
||
}
|
||
return list;
|
||
}
|
||
|
||
showUpdateChannelNameDialog(BuildContext context) {
|
||
showDialog(
|
||
context: context,
|
||
builder: (BuildContext context) => InputDialog(
|
||
title: const Text("请输入群名称"),
|
||
isOnlyText: true,
|
||
hintText: '请输入群名称',
|
||
back: (name, channelType) {
|
||
HttpUtils.updateGroupName(channelID, name);
|
||
},
|
||
),
|
||
);
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
super.dispose();
|
||
// 移出监听
|
||
WKIM.shared.messageManager.removeNewMsgListener('chat');
|
||
WKIM.shared.messageManager.removeOnRefreshMsgListener('chat');
|
||
WKIM.shared.messageManager.removeDeleteMsgListener('chat');
|
||
WKIM.shared.channelManager.removeOnRefreshListener('chat');
|
||
}
|
||
}
|
||
|
||
Widget _buildItem(UIMsg uiMsg, BuildContext context) {
|
||
return GestureDetector(
|
||
onTap: () {
|
||
Navigator.push(
|
||
context,
|
||
MaterialPageRoute(
|
||
builder: (context) => const ChatPage(),
|
||
settings: RouteSettings(
|
||
arguments: ChatChannel(
|
||
uiMsg.wkMsg.channelID,
|
||
uiMsg.wkMsg.channelType,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
},
|
||
child: Container(
|
||
padding: const EdgeInsets.all(10),
|
||
child: Row(
|
||
children: [
|
||
ClipRRect(
|
||
borderRadius: BorderRadius.circular(20),
|
||
child: Image.network(
|
||
getChannelAvatarURL(uiMsg),
|
||
height: 50,
|
||
width: 50,
|
||
fit: BoxFit.cover,
|
||
errorBuilder: (BuildContext context, Object exception,
|
||
StackTrace? stackTrace) {
|
||
return ClipRRect(
|
||
borderRadius: BorderRadius.circular(20),
|
||
child: Image.asset(
|
||
'assets/ic_default_avatar.png',
|
||
width: 50,
|
||
height: 50,
|
||
),
|
||
);
|
||
},
|
||
),
|
||
),
|
||
const SizedBox(width: 10),
|
||
Expanded(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
uiMsg.wkMsg.getFrom()?.channelName ?? '未知用户',
|
||
style: const TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
const SizedBox(height: 4),
|
||
Text(
|
||
uiMsg.getShowContent(),
|
||
style: const TextStyle(
|
||
fontSize: 14,
|
||
color: Colors.grey,
|
||
),
|
||
maxLines: 1,
|
||
overflow: TextOverflow.ellipsis,
|
||
),
|
||
],
|
||
),
|
||
),
|
||
Text(
|
||
uiMsg.getShowTime(),
|
||
style: const TextStyle(
|
||
fontSize: 12,
|
||
color: Colors.grey,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|