Browse Source

Merge remote-tracking branch 'origin/wr_202303' into wr_202303

wr_202303
wurong 4 months ago
parent
commit
c5ed90325e
  1. 84
      lib/im/SocketClient.dart
  2. 131
      lib/im/chat_details_page.dart
  3. 38
      lib/im/database/message.dart

84
lib/im/SocketClient.dart

@ -11,6 +11,8 @@ import 'package:huixiang/im/database/message.dart';
import 'package:huixiang/im/out/auth.pb.dart'; import 'package:huixiang/im/out/auth.pb.dart';
import 'package:huixiang/im/out/message.pb.dart'; import 'package:huixiang/im/out/message.pb.dart';
import 'package:huixiang/main.dart'; import 'package:huixiang/main.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
class SocketClient { class SocketClient {
@ -42,20 +44,19 @@ class SocketClient {
MsgData dataResult = MsgData.fromBuffer(proto.body); MsgData dataResult = MsgData.fromBuffer(proto.body);
print('收到来自:${dataResult.from},消息内容: ${utf8.decode(dataResult.data)} '); print('收到来自:${dataResult.from},消息内容: ${utf8.decode(dataResult.data)} ');
Map<String, dynamic> messageMap = createMessage(userId, dataResult.data, msgType: dataResult.type.value, userId: dataResult.from); receiveInsertMessage(dataResult).then((messageMap) {
if (callbacks[dataResult.from] != null) {
messageMap["state"] = 1;
}
hxDatabase.insert(messageMap).then((value) {
messageMap["id"] = value;
Message message = Message.fromJson(messageMap);
if (callbacks[dataResult.from] != null) { if (callbacks[dataResult.from] != null) {
callbacks[dataResult.from].call(message); /// user conversation callback messageMap["state"] = 1;
} }
callbacks[userId]?.call(message); /// user self conversation list callback hxDatabase.insert(messageMap).then((value) {
messageMap["id"] = value;
Message message = Message.fromJson(messageMap);
if (callbacks[dataResult.from] != null) {
callbacks[dataResult.from].call(message); /// user conversation callback
}
callbacks[userId]?.call(message); /// user self conversation list callback
});
}); });
}, onError: (Object error, StackTrace stackTrace) { }, onError: (Object error, StackTrace stackTrace) {
debugPrint("socket-listen-error: $error, stackTrace: $stackTrace"); debugPrint("socket-listen-error: $error, stackTrace: $stackTrace");
showDebugToast("socket-listen-error: $error, stackTrace: $stackTrace"); showDebugToast("socket-listen-error: $error, stackTrace: $stackTrace");
@ -75,6 +76,42 @@ class SocketClient {
}); });
} }
Future<Map<String, dynamic>> receiveInsertMessage(MsgData dataResult) async {
String content = "";
String attach = "";
Uint8List dataBytes = dataResult.data;
MsgType type = MsgType.values[dataResult.type.value];
if (type == MsgType.TEXT) {
content = utf8.decode(dataBytes);
} else if (type == MsgType.IMAGE || type == MsgType.VIDEO) {
Map<String, dynamic> result = await ImageGallerySaver.saveImage(
dataBytes,
isReturnImagePathOfIOS: true,
);
bool isSuccess = result["isSuccess"] != null && result["isSuccess"];
if (isSuccess) {
attach = result["filePath"];
}
} else if (type == MsgType.AUDIO) {
Directory dir = await getTemporaryDirectory();
File file = File("${dir.path}/hx_${DateTime.now().millisecondsSinceEpoch}.wav");
try {
IOSink ioSink = file.openWrite();
ioSink.write(dataBytes);
ioSink.close();
attach = file.path;
} catch (e) {
debugPrint("${file.path} write fail");
}
} else {
content = "暂不支持的消息格式";
}
Map<String, dynamic> messageMap = createMessage(userId, content, attach: attach, msgType: type.value, fromId: dataResult.from);
return messageMap;
}
showDebugToast(text) { showDebugToast(text) {
if (kDebugMode) { if (kDebugMode) {
SmartDialog.showToast(text, alignment: Alignment.center); SmartDialog.showToast(text, alignment: Alignment.center);
@ -171,8 +208,23 @@ class SocketClient {
} }
} }
Future<Message> sendMessage(String toId, String content) async { Future<Message> sendMessage(String toId, String content, {String attach, int msgType, replyId}) async {
Map<String, dynamic> message = createSendMessage(toId, content, userId: userId);
MsgType type = MsgType.values[msgType];
Uint8List data;
if (type == MsgType.TEXT) {
data = utf8.encode(content);
} else if (type == MsgType.IMAGE || type == MsgType.VIDEO || type == MsgType.AUDIO) {
File file = File(attach);
Directory dir = await getTemporaryDirectory();
File newFile = await file.copy("${dir.path}/hx_${DateTime.now().millisecondsSinceEpoch}.${file.path.split(".")[1]}");
data = await file.readAsBytes();
attach = newFile.path;
} else {
data = utf8.encode(content);
}
Map<String, dynamic> message = createMessage(toId, content, fromId: userId, attach: attach, msgType: msgType, replyId: replyId);
message["state"] = 1; message["state"] = 1;
int id = await hxDatabase.insert(message).catchError((error) { int id = await hxDatabase.insert(message).catchError((error) {
debugPrint("insertMessage: $error"); debugPrint("insertMessage: $error");
@ -186,8 +238,8 @@ class SocketClient {
return Message.fromJson(message); return Message.fromJson(message);
} }
message["id"] = id; message["id"] = id;
Uint8List data = utf8.encode(content);
MsgData msgData = MsgData(to: toId, from: userId, type: MsgType.TEXT, data: data); MsgData msgData = MsgData(to: toId, from: userId, type: type, data: data);
final proto2 = Proto(5, 1, msgData.writeToBuffer()); final proto2 = Proto(5, 1, msgData.writeToBuffer());
try { try {
_socket.add(proto2.toBytes()); _socket.add(proto2.toBytes());
@ -202,6 +254,8 @@ class SocketClient {
return Message.fromJson(message); return Message.fromJson(message);
} }
checkSocket() { checkSocket() {
if (_socket == null) { if (_socket == null) {
reconnect(); reconnect();

131
lib/im/chat_details_page.dart

@ -312,6 +312,12 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
} else { } else {
dynamicType = 2; dynamicType = 2;
} }
List<String> filePath = mediaPaths.map((e) => e.path).toList();
filePath.forEach((path) {
socketClient.sendMessage(_toUser.mid, "", attach: path, msgType: galleryMode == GalleryMode.image ? 2 : 4);
});
} }
setState(() {}); setState(() {});
} }
@ -428,6 +434,7 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
Widget chatDetailsItem(position) { Widget chatDetailsItem(position) {
bool isSelf = messages[position].fromId == selfUserId; bool isSelf = messages[position].fromId == selfUserId;
bool isText = messages[position].msgType == 1; bool isText = messages[position].msgType == 1;
bool isImage = messages[position].msgType == 2;
return Container( return Container(
padding: EdgeInsets.only( padding: EdgeInsets.only(
top: 16.h, top: 16.h,
@ -570,11 +577,13 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
GestureDetector( GestureDetector(
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
onTap: () { onTap: () {
Navigator.of(context).pushNamed('/router/personal_page', Navigator.of(context).pushNamed(
arguments: { '/router/personal_page',
"memberId": _toUser?.mid ?? "", arguments: {
"inletType": 1 "memberId": _toUser?.mid ?? "",
}); "inletType": 1
},
);
}, },
child: MImage( child: MImage(
_toUser.avatar, _toUser.avatar,
@ -584,7 +593,8 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
fit: BoxFit.cover, fit: BoxFit.cover,
errorSrc: "assets/image/default_1.webp", errorSrc: "assets/image/default_1.webp",
fadeSrc: "assets/image/default_1.webp", fadeSrc: "assets/image/default_1.webp",
)), ),
),
SizedBox( SizedBox(
width: 12.w, width: 12.w,
), ),
@ -807,30 +817,26 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
fit: BoxFit.cover, fit: BoxFit.cover,
errorSrc: "assets/image/default_1.webp", errorSrc: "assets/image/default_1.webp",
fadeSrc: "assets/image/default_1.webp", fadeSrc: "assets/image/default_1.webp",
)), ),
),
], ],
), ),
), ),
/// not self image /// not self image
if (!isSelf && !isText) if (!isSelf && isImage)
Padding( Padding(
padding: EdgeInsets.only(left: 17.w, right: 39.w, top: 20.h), padding: EdgeInsets.only(left: 17.w, right: 39.w, top: 20.h),
child: Row( child: Row(
children: [ children: [
// MImage( MImage(
// "", userInfo?.headimg ?? "",
// isCircle: true, isCircle: true,
// width: 44, width: 44,
// height: 44, height: 44,
// fit: BoxFit.cover, fit: BoxFit.cover,
// errorSrc: "assets/image/default_1.webp", errorSrc: "assets/image/default_1.webp",
// fadeSrc: "assets/image/default_1.webp", fadeSrc: "assets/image/default_1.webp",
// ),
Image.asset(
"assets/image/fuka_zj.webp",
height: 44.h,
width: 44.h,
), ),
SizedBox( SizedBox(
width: 12.w, width: 12.w,
@ -847,24 +853,74 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
offset: Offset(0, 4), offset: Offset(0, 4),
blurRadius: 4, blurRadius: 4,
spreadRadius: 0, spreadRadius: 0,
) ),
], ],
), ),
child: GestureDetector( child: GestureDetector(
onLongPress: () { onLongPress: () {
setState(() {}); setState(() {});
}, },
child: Image.asset( child: Image.file(
"assets/image/icon_guide_4.webp", File(messages[position].attach),
width: 180.h, width: 180.h,
height: 200.h, height: 200.h,
fit: BoxFit.fill, fit: BoxFit.fill,
), ),
))), ),
),
),
Spacer(),
],
),
),
/// self image
if (isSelf && isImage)
Padding(
padding: EdgeInsets.only(left: 39.w, right: 17.w, top: 20.h),
child: Row(
children: [
Spacer(),
Expanded( Expanded(
flex: 1, flex: 3,
child: Container(), child: Container(
) decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: Color(0xFFFFFFFF),
boxShadow: [
BoxShadow(
color: Color(0xFFA8A3A3).withAlpha(12),
offset: Offset(0, 4),
blurRadius: 4,
spreadRadius: 0,
),
],
),
child: GestureDetector(
onLongPress: () {
setState(() {});
},
child: Image.file(
File(messages[position].attach),
width: 180.h,
height: 200.h,
fit: BoxFit.fill,
),
),
),
),
SizedBox(
width: 12.w,
),
MImage(
userInfo?.headimg ?? "",
isCircle: true,
width: 44,
height: 44,
fit: BoxFit.cover,
errorSrc: "assets/image/default_1.webp",
fadeSrc: "assets/image/default_1.webp",
),
], ],
), ),
), ),
@ -922,8 +978,7 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
if (commentText.trim() == "") { if (commentText.trim() == "") {
return; return;
} }
socketClient socketClient.sendMessage(_toUser.mid, commentText)
.sendMessage(_toUser.mid, commentText)
.then((value) { .then((value) {
Message message = value; Message message = value;
messages.insert(0, message); messages.insert(0, message);
@ -962,14 +1017,15 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
"assets/image/icon_chat_emo.webp", "assets/image/icon_chat_emo.webp",
height: 26.h, height: 26.h,
width: 26.h, width: 26.h,
)), ),
),
), ),
GestureDetector( GestureDetector(
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
onTap: () { onTap: () {
// _onMoreTap(); _onMoreTap();
// jumpToBottom(); jumpToBottom();
SmartDialog.showToast("暂不支持", alignment: Alignment.center); // SmartDialog.showToast("暂不支持", alignment: Alignment.center);
}, },
child: Container( child: Container(
padding: EdgeInsets.only(left: 8.w, right: 19.w), padding: EdgeInsets.only(left: 8.w, right: 19.w),
@ -1123,13 +1179,14 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
), ),
), ),
], ],
)), ),
),
], ],
) ),
], ],
), ),
), ),
) ),
], ],
), ),
); );

38
lib/im/database/message.dart

@ -1,5 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'dart:typed_data'; import 'dart:typed_data';
@ -7,6 +8,7 @@ import 'package:flutter/cupertino.dart';
import 'package:huixiang/im/out/message.pb.dart'; import 'package:huixiang/im/out/message.pb.dart';
import 'package:huixiang/im/out/message.pbenum.dart'; import 'package:huixiang/im/out/message.pbenum.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:path_provider/path_provider.dart';
class Message { class Message {
int id; int id;
@ -64,10 +66,10 @@ class Message {
}; };
} }
createSendMessage(var toId, String content, {String attach, int msgType, userId, replyId}) { createMessage(var toId, String content, {String attach, int msgType, fromId, replyId}) {
return <String, dynamic>{ return <String, dynamic>{
"conversationId": conversationId(userId, toId), "conversationId": conversationId(fromId, toId),
"fromId": userId, "fromId": fromId,
"toId": toId, "toId": toId,
"replyId": replyId, "replyId": replyId,
"content": content, "content": content,
@ -79,36 +81,6 @@ createSendMessage(var toId, String content, {String attach, int msgType, userId,
}; };
} }
createMessage(var toId, Uint8List dataBytes, {String attach, int msgType, userId, replyId}) {
String content = "";
MsgType type = MsgType.values[msgType];
if (type == MsgType.TEXT) {
content = utf8.decode(dataBytes);
}
if (type == MsgType.IMAGE || type == MsgType.AUDIO || type == MsgType.VIDEO) {
Map<String, dynamic> result = ImageGallerySaver.saveImage(
dataBytes,
isReturnImagePathOfIOS: true,
);
bool isSuccess = result["isSuccess"] != null && result["isSuccess"];
if (isSuccess) {
attach = result["filePath"];
}
}
return <String, dynamic>{
"conversationId": conversationId(userId, toId),
"fromId": userId,
"toId": toId,
"replyId": replyId,
"content": content,
"attach": attach,
"msgType": msgType ?? 1,
"time": "${DateTime.now().millisecondsSinceEpoch}",
"state": 0,
"isDelete": 0
};
}
conversationId(tid, fid) { conversationId(tid, fid) {
num itid = num.parse(tid); num itid = num.parse(tid);

Loading…
Cancel
Save