diff --git a/lib/im/SocketClient.dart b/lib/im/SocketClient.dart index 0f169bf1..0396afcd 100644 --- a/lib/im/SocketClient.dart +++ b/lib/im/SocketClient.dart @@ -16,7 +16,7 @@ import 'package:shared_preferences/shared_preferences.dart'; class SocketClient { //47.93.216.24:9090 线上 192.168.10.129:9090 测试 - final String ip = kDebugMode ? '192.168.10.129' : '47.93.216.24'; + final String ip = !kDebugMode ? '192.168.10.129' : '47.93.216.24'; final num port = 9090; Socket _socket; SharedPreferences _shared; @@ -42,7 +42,8 @@ class SocketClient { MsgData dataResult = MsgData.fromBuffer(proto.body); print('收到来自:${dataResult.from},消息内容: ${utf8.decode(dataResult.data)} '); - Map messageMap = createMessage(userId, utf8.decode(dataResult.data), msgType: dataResult.type.value, userId: dataResult.from); + Map messageMap = createMessage(userId, dataResult.data, msgType: dataResult.type.value, userId: dataResult.from); + if (callbacks[dataResult.from] != null) { messageMap["state"] = 1; } @@ -54,6 +55,7 @@ class SocketClient { } callbacks[userId]?.call(message); /// user self conversation list callback }); + }, onError: (Object error, StackTrace stackTrace) { debugPrint("socket-listen-error: $error, stackTrace: $stackTrace"); showDebugToast("socket-listen-error: $error, stackTrace: $stackTrace"); @@ -152,17 +154,26 @@ class SocketClient { if (!checkSocket()) { return; } + debugPrint("socket-authRequest: request"); final authReq = AuthReq() ..uid = userId ..token = token; final authReqBytes = authReq.writeToBuffer(); final proto = Proto(1, 1, authReqBytes); // 假设 operation 和 seqId 为 1 final protoBytes = proto.toBytes(); - _socket.add(protoBytes); + try { + _socket.add(protoBytes); + } catch (e) { + debugPrint("socket-authRequest: $e"); + Future.delayed(const Duration(milliseconds: 1000), () { + authRequest(token); + }); + } } Future sendMessage(String toId, String content) async { - Map message = createMessage(toId, content, userId: userId); + Map message = createSendMessage(toId, content, userId: userId); + message["state"] = 1; int id = await hxDatabase.insert(message).catchError((error) { debugPrint("insertMessage: $error"); }); @@ -188,7 +199,6 @@ class SocketClient { showDebugToast("socket-send-error: ${e.toString()}"); reconnect(); } - debugPrint("sendMessage: ${message["id"]}"); return Message.fromJson(message); } diff --git a/lib/im/chat_details_page.dart b/lib/im/chat_details_page.dart index dd072390..859e4c20 100644 --- a/lib/im/chat_details_page.dart +++ b/lib/im/chat_details_page.dart @@ -105,19 +105,19 @@ class _ChatDetailsPage extends State Future refresh() async { List messagePage = await hxDatabase.queryUList(conversation, page: page + 1, pageSize: 10); - page += 1; - if (page == 1) { - messages = messagePage; - } else { - messages.addAll(messagePage); - } - await messageShowTime(); if (messagePage.isEmpty) { refreshController.loadNoData(); return; } else { refreshController.loadComplete(); + page += 1; } + if (page == 1) { + messages = messagePage; + } else { + messages.addAll(messagePage); + } + await messageShowTime(); return Future.value(); } @@ -177,7 +177,7 @@ class _ChatDetailsPage extends State void jumpToBottom() { Future.delayed(const Duration(milliseconds: 100), () { scrollController.position - .jumpTo(scrollController.position.maxScrollExtent); + .jumpTo(0); }); } @@ -374,32 +374,28 @@ class _ChatDetailsPage extends State enablePullDown: false, enablePullUp: true, header: MyHeader(), - reverse: true, - physics: BouncingScrollPhysics(), footer: CustomFooter( loadStyle: LoadStyle.ShowWhenLoading, builder: (BuildContext context, LoadStatus mode) { return SizedBox(); }, ), + reverse: true, + scrollController: scrollController, controller: refreshController, + onRefresh: () { + debugPrint(""); + }, onLoading: () { refresh().then((value) { refreshState(); }); }, - child: Container( - alignment: Alignment.topCenter, - child: SingleChildScrollView( - physics: BouncingScrollPhysics(), - controller: scrollController, - child: chatDetailsList(), - ), - ), + child: chatDetailsList(), ), flex: 1, ), - input() + input(), ], ), ), @@ -409,27 +405,22 @@ class _ChatDetailsPage extends State ///聊天列表 Widget chatDetailsList() { - return Container( - alignment: Alignment.topCenter, - child: ListView.builder( - itemCount: messages.length, - shrinkWrap: true, - reverse: true, - padding: EdgeInsets.zero, - physics: NeverScrollableScrollPhysics(), - itemBuilder: (context, position) { - return GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () { - setState(() { - copyIndex = 0; - FocusScope.of(context).requestFocus(FocusNode()); - }); - }, - child: chatDetailsItem(position), - ); - }, - ), + return ListView.builder( + itemCount: messages.length, + reverse: true, + padding: EdgeInsets.zero, + itemBuilder: (context, position) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + setState(() { + copyIndex = 0; + FocusScope.of(context).requestFocus(FocusNode()); + }); + }, + child: chatDetailsItem(position), + ); + }, ); } @@ -936,8 +927,10 @@ class _ChatDetailsPage extends State Message message = value; messages.insert(0, message); chatController.clear(); - refreshState(); - jumpToBottom(); + messageShowTime().then((value) { + refreshState(); + jumpToBottom(); + }); }); }, maxLines: 8, @@ -1028,7 +1021,8 @@ class _ChatDetailsPage extends State buttonMode: ButtonMode.MATERIAL, checkPlatformCompatibility: true, ), - )), + ), + ), ), ///更多 @@ -1227,4 +1221,5 @@ class _ChatDetailsPage extends State print(tex); Clipboard.setData(ClipboardData(text: tex)); } + } diff --git a/lib/im/chat_setting.dart b/lib/im/chat_setting.dart index 75dbe0f9..5f8654ce 100644 --- a/lib/im/chat_setting.dart +++ b/lib/im/chat_setting.dart @@ -5,9 +5,11 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:huixiang/im/database/message.dart'; import 'package:huixiang/retrofit/retrofit_api.dart'; import 'package:huixiang/view_widget/my_appbar.dart'; import 'package:flutter/cupertino.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import '../../generated/l10n.dart'; import '../../utils/font_weight.dart'; import '../main.dart'; @@ -26,6 +28,7 @@ class ChatSetting extends StatefulWidget { class _ChatSetting extends State { ImUser imUser; + String selfUserId = ""; @override void initState() { @@ -34,6 +37,7 @@ class _ChatSetting extends State { } void initData() async { + selfUserId = (await SharedPreferences.getInstance()).getString("userId"); imUser = await hxDatabase.queryImUserById(widget.arguments["userId"]); setState(() { @@ -79,8 +83,7 @@ class _ChatSetting extends State { onChanged: (bool value) async { if (imUser == null) return; imUser.isTop = value ? 1 : 0; - await hxDatabase - .insertOrUpdateImUser(imUser.toJson()); + await hxDatabase.insertOrUpdateImUser(imUser.toJson()); setState(() {}); }, ), @@ -112,8 +115,7 @@ class _ChatSetting extends State { ], ), onTap: () async { - await hxDatabase - .deleteByUser(widget.arguments["userId"] ?? ""); + await hxDatabase.deleteByUser(conversationId(widget.arguments["userId"] ?? "", selfUserId)); // SmartDialog.showToast("删除成功", // alignment: Alignment.center); }, diff --git a/lib/im/database/hx_database.dart b/lib/im/database/hx_database.dart index 4f703968..585be2e9 100644 --- a/lib/im/database/hx_database.dart +++ b/lib/im/database/hx_database.dart @@ -11,15 +11,15 @@ class HxDatabase { Database db; void open({String key}) async { - // _migrations.add(Migration(1, 2, (Database database) async { - // database.execute('ALTER TABLE `Message` ADD COLUMN `replyId` VARCHAR(20) DEFAULT NULL AFTER `toId`'); + // _migrations.add(Migration(3, 4, (Database database) async { + // await database.execute('ALTER TABLE ImUser ADD COLUMN IF NOT EXISTS `isTop` INTEGER DEFAULT 0'); // })); String databaseName = 'hx.db'; if (key?.isNotEmpty ?? false) { databaseName = 'hx_$key.db'; } - await openDatabase(databaseName, version: 2, + await openDatabase(databaseName, version: 1, onCreate: (Database db, int version) async { db.execute( 'CREATE TABLE IF NOT EXISTS `Message` (`id` INTEGER, `conversationId` VARCHAR(40), `fromId` VARCHAR(20), `toId` VARCHAR(20), `replyId` VARCHAR(20), `content` TEXT, `attach` TEXT, `msgType` INTEGER, `time` VARCHAR(20), `state` INTEGER, `isDelete` INTEGER, PRIMARY KEY (`id`))'); @@ -27,10 +27,7 @@ class HxDatabase { 'CREATE TABLE IF NOT EXISTS `ImUser` (`id` INTEGER, `mid` VARCHAR(20), `nickname` VARCHAR(20), `avatar` VARCHAR(200), `phone` VARCHAR(200), `isDelete` INTEGER, `isTop` INTEGER, PRIMARY KEY (`id`))'); }, onConfigure: (database) async { await database.execute('PRAGMA foreign_keys = ON'); - try { - await database.execute( - 'ALTER TABLE ImUser ADD COLUMN isTop INTEGER DEFAULT 0'); - }catch (e){} + debugPrint("database-version: ${await database.getVersion()}"); }, onUpgrade: (database, startVersion, endVersion) async { await runMigrations(database, startVersion, endVersion, _migrations); }, onOpen: (Database db) { @@ -51,10 +48,8 @@ class HxDatabase { Future lastMessage(String conversationId) async { await _dbIsOpen(); - String sql = - 'SELECT * FROM Message WHERE conversationId = ? ORDER BY time DESC LIMIT 1'; - List messages = - await db.rawQuery(sql, [conversationId]).then((value) { + String sql = 'SELECT * FROM Message WHERE conversationId = ? ORDER BY time DESC LIMIT 1'; + List messages = await db.rawQuery(sql, [conversationId]).then((value) { return value.map((e) { debugPrint("Message: $e"); return Message.fromJson(e); @@ -89,7 +84,7 @@ class HxDatabase { return Message.fromJson(e); }).toList(); }, onError: (error) { - debugPrint("MessageError: $error"); + debugPrint("Message-error: $error"); }); } @@ -100,7 +95,7 @@ class HxDatabase { return db.rawQuery(sql, [conversationId, start, pageSize]).then((value) { return value.map((e) => Message.fromJson(e)).toList(); }, onError: (error) { - debugPrint("Messageerror: $error"); + debugPrint("Message-error: $error"); }); } @@ -110,7 +105,7 @@ class HxDatabase { return db.rawQuery(sql, [conversationId]).then((value) { return value.map((e) => Message.fromJson(e)).toList(); }, onError: (error) { - debugPrint("Messageerror: $error"); + debugPrint("Message-error: $error"); }); } @@ -118,14 +113,18 @@ class HxDatabase { await _dbIsOpen(); String userStr = conversationIds.join(","); debugPrint("userStr: $userStr"); - List messages = await db.rawQuery( - "SELECT * FROM Message WHERE `conversationId` IN ($userStr) AND state = 0 AND isDelete = 0", + List messages = await db.query("Message", + where: "`conversationId` IN (?) AND state = 0 AND isDelete = 0", + whereArgs: [userStr], ).then((value) { return value.map((e) => Message.fromJson(e)).toList(); }, onError: (error) { debugPrint("Message-error: $error"); }); - return (messages??[]).lGroupBy((p) => p.fromId).mGroupCount; + messages.forEach((element) { + debugPrint("messageUnreadCount: ${element.toJson()}"); + }); + return (messages??[]).lGroupBy((p) => p.conversationId).mGroupCount; } Future> queryListAll() async{ diff --git a/lib/im/database/message.dart b/lib/im/database/message.dart index 32c6d641..9f5b13c1 100644 --- a/lib/im/database/message.dart +++ b/lib/im/database/message.dart @@ -1,5 +1,12 @@ +import 'dart:convert'; import 'dart:math'; +import 'dart:typed_data'; + +import 'package:flutter/cupertino.dart'; +import 'package:huixiang/im/out/message.pb.dart'; +import 'package:huixiang/im/out/message.pbenum.dart'; +import 'package:image_gallery_saver/image_gallery_saver.dart'; class Message { int id; @@ -57,7 +64,39 @@ class Message { }; } -createMessage(var toId, String content, {String attach, int msgType, userId, replyId}) { +createSendMessage(var toId, String content, {String attach, int msgType, userId, replyId}) { + return { + "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 + }; +} + +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 result = ImageGallerySaver.saveImage( + dataBytes, + isReturnImagePathOfIOS: true, + ); + bool isSuccess = result["isSuccess"] != null && result["isSuccess"]; + if (isSuccess) { + attach = result["filePath"]; + } + } + + return { "conversationId": conversationId(userId, toId), "fromId": userId, diff --git a/lib/im/im_view/im_page.dart b/lib/im/im_view/im_page.dart index c0d0612e..f775ae7c 100644 --- a/lib/im/im_view/im_page.dart +++ b/lib/im/im_view/im_page.dart @@ -139,6 +139,7 @@ class _IMPage extends State implements OnChatMessage { /// update conversation unreadcount queryUnreadCount(conversationIds) async { unreadCountMap = await hxDatabase.messageUnreadCount(conversationIds); + debugPrint("unreadCountMap: $unreadCountMap"); } /// update imuser info by mids @@ -169,7 +170,7 @@ class _IMPage extends State implements OnChatMessage { /// update one conversation last message ,and update conversation sort void updateLastMessage(String conversationId) async { Message message = await hxDatabase.lastMessage(conversationId); - debugPrint("lastmessage: $conversationId ${message.content} ${message.toJson()}"); + debugPrint("lastmessage: $conversationId ${message?.content} ${message?.toJson()}"); if (message != null) { lastMessageMap[conversationId] = message; await sortConversation(lastMessageMap); diff --git a/lib/retrofit/min_api.dart b/lib/retrofit/min_api.dart index 0115d920..f34e728b 100644 --- a/lib/retrofit/min_api.dart +++ b/lib/retrofit/min_api.dart @@ -27,8 +27,9 @@ import 'data/shopping_home_config.dart'; part 'min_api.g.dart'; -const localBaseUrl = "http://192.168.10.54:8765/app/";///本地 +// const localBaseUrl = "http://192.168.10.54:8765/app/";///本地 // const localBaseUrl = "http://pos-test.api.lotus-wallet.com/app/";///测试 +const localBaseUrl = "https://pos.api.lotus-wallet.com/app/";///线上 const serviceBaseUrl = "https://pos.api.lotus-wallet.com/app/";///线上 @@ -44,8 +45,7 @@ abstract class MinApiService { String storeId, bool showLoading = false, }) { - Map headers = - (token == null || token == "") ? {} : {'token': "Bearer $token"}; + Map headers = (token == null || token == "") ? {} : {'token': "Bearer $token"}; if (tenant != null && tenant != "") { headers["tenant"] = tenant; } diff --git a/lib/retrofit/retrofit_api.dart b/lib/retrofit/retrofit_api.dart index a7a07276..e569623f 100644 --- a/lib/retrofit/retrofit_api.dart +++ b/lib/retrofit/retrofit_api.dart @@ -70,13 +70,13 @@ import 'data/wx_pay.dart'; part 'retrofit_api.g.dart'; -const localBaseUrl = "http://192.168.10.54:8766/app/";///本地 +// const localBaseUrl = "http://192.168.10.54:8766/app/";///本地 // const localBaseUrl = "http://platform.test.api.lotus-wallet.com/app/";///测试 +const localBaseUrl = "https://pos.platform.lotus-wallet.com/app/";///线上 const serviceBaseUrl = "https://pos.platform.lotus-wallet.com/app/";///线上 const ipBaseUrl = "http://whois.pconline.com.cn"; -///ip @RestApi(baseUrl: localBaseUrl) abstract class ApiService { diff --git a/lib/utils/upload_async.dart b/lib/utils/upload_async.dart index 14188069..d1e62507 100644 --- a/lib/utils/upload_async.dart +++ b/lib/utils/upload_async.dart @@ -34,7 +34,8 @@ class UploadAsync { decoration: BoxDecoration( color: Colors.grey, borderRadius: BorderRadius.circular(2)), child: dynamicType == 0 - ? Expanded(child: Column( + ? Expanded( + child: Column( children: [ Text( dynamicText, @@ -49,8 +50,8 @@ class UploadAsync { Expanded(child: Container( height: 20.h, - )) - ])) + ),), + ],),) : ClipRRect( borderRadius: BorderRadius.circular(2), child: Image.file(