Browse Source

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

wr_202303
wurong 4 months ago
parent
commit
ce187025a9
  1. 8
      android/app/build.gradle
  2. 34
      android/build.gradle
  3. 9
      android/gradle.properties
  4. 2
      android/gradle/wrapper/gradle-wrapper.properties
  5. 26
      ios/Podfile.lock
  6. 15
      ios/Runner.xcodeproj/project.pbxproj
  7. 72
      lib/im/Proto.dart
  8. 110
      lib/im/SocketClient.dart
  9. 728
      lib/im/chat_details_page.dart
  10. 123
      lib/im/database/hx_database.dart
  11. 146
      lib/im/database/hx_database.g.dart
  12. 63
      lib/im/database/message.dart
  13. 17
      lib/im/database/message_dao.dart
  14. 41
      lib/im/database/migration.dart
  15. 294
      lib/im/im_view/im_page.dart
  16. 160
      lib/im/out/auth.pb.dart
  17. 11
      lib/im/out/auth.pbenum.dart
  18. 43
      lib/im/out/auth.pbjson.dart
  19. 14
      lib/im/out/auth.pbserver.dart
  20. 272
      lib/im/out/message.pb.dart
  21. 36
      lib/im/out/message.pbenum.dart
  22. 85
      lib/im/out/message.pbjson.dart
  23. 14
      lib/im/out/message.pbserver.dart
  24. 12
      lib/main.dart
  25. 11
      lib/main_page.dart
  26. 3
      lib/message/mine_message.dart
  27. 1
      lib/mine/edit_signature.dart
  28. 112
      pubspec.lock
  29. 5
      pubspec.yaml

8
android/app/build.gradle

@ -27,7 +27,7 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
apply plugin: 'com.mob.sdk'
apply plugin: 'com.huawei.agconnect'
//apply plugin: 'com.huawei.agconnect'
MobSDK {
appKey "m33ee7650da86a"
@ -106,7 +106,7 @@ android {
defaultConfig {
applicationId "com.zsw.huixiang"
minSdkVersion 21
targetSdkVersion 31
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
@ -203,7 +203,7 @@ dependencies {
implementation 'com.tencent.tpns:xiaomi:1.2.7.1-release'
implementation 'com.tencent.tpns:huawei:1.2.6.0-release'
// implementation 'com.tencent.tpns:huawei:1.2.6.0-release'
// HMS Core Push
implementation 'com.huawei.hms:push:5.3.0.304'
// implementation 'com.huawei.hms:push:5.3.0.304'
}

34
android/build.gradle

@ -1,6 +1,9 @@
buildscript {
ext.kotlin_version = '1.7.10'
ext.kotlin_version = '1.8.10'
repositories {
maven { url "https://www.jitpack.io" }
maven {url 'https://developer.huawei.com/repo/'}
maven { url 'https://repo1.maven.org/maven2/' }
maven {
url 'https://maven.aliyun.com/repository/google'
}
@ -11,28 +14,22 @@ buildscript {
allowInsecureProtocol = true
url 'http://maven.aliyun.com/nexus/content/groups/public'
}
// google()
// jcenter()
maven {
allowInsecureProtocol = true
url "http://mvn.mob.com/android"
}
maven { url "https://www.jitpack.io" }
maven {url 'https://developer.huawei.com/repo/'}
maven { url 'https://repo1.maven.org/maven2/' }
maven { url 'https://developer.huawei.com/repo/' }
}
dependencies {
// classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.android.tools.build:gradle:7.2.0'
classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
// classpath 'com.huawei.agconnect:agcp:1.4.1.300'
classpath 'com.mob.sdk:MobSDK:+'
classpath 'com.android.tools.build:gradle:3.4.0'
classpath fileTree(include:['*.jar'], dir:'libs')
classpath 'com.umeng.umsdk:common:9.4.7'
classpath 'com.umeng.umsdk:asms:1.4.0'
classpath 'com.umeng.umsdk:abtest:1.0.0'
classpath 'com.umeng.umsdk:common:9.4.7'
classpath 'com.umeng.umsdk:asms:1.4.0'
classpath 'com.umeng.umsdk:abtest:1.0.0'
}
}
@ -41,22 +38,15 @@ allprojects {
maven {
url 'https://maven.aliyun.com/repository/google'
}
maven {
url 'https://maven.aliyun.com/repository/jcenter'
}
maven {
allowInsecureProtocol = true
url 'http://maven.aliyun.com/nexus/content/groups/public'
}
// google()
// jcenter()
maven {
allowInsecureProtocol = true
url "http://mvn.mob.com/android"
}
maven { url "https://www.jitpack.io" }
maven { url 'https://developer.huawei.com/repo/'}
maven { url 'https://repo1.maven.org/maven2/' }
google()
}
}
@ -66,6 +56,6 @@ subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}

9
android/gradle.properties

@ -1,10 +1,7 @@
org.gradle.jvmargs=-Xmx1536M
#org.gradle.jvmargs=-Xmx4096m
#org.gradle.jvmargs=-Xmx1536M
org.gradle.jvmargs=-Xmx4096m
android.useAndroidX=true
android.enableJetifier=true
MobSDK.mobEnv=x
MobSDK.spEdition=FP
android.injected.testOnly=false
#org.gradle.jvmargs=-Xmx1536M --add-exports=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED
android.injected.testOnly=false

2
android/gradle/wrapper/gradle-wrapper.properties vendored

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

26
ios/Podfile.lock

@ -22,6 +22,9 @@ PODS:
- fluwx (0.0.1):
- Flutter
- "OpenWeChatSDK (~> 1.9.2+1)"
- FMDB (2.7.11):
- FMDB/standard (= 2.7.11)
- FMDB/standard (2.7.11)
- geolocator (6.2.0):
- Flutter
- image_gallery_saver (2.0.2):
@ -56,7 +59,7 @@ PODS:
- "OpenWeChatSDK (1.9.9+1)"
- package_info (0.0.1):
- Flutter
- path_provider (0.0.1):
- path_provider_ios (0.0.1):
- Flutter
- "permission_handler (5.1.0+2)":
- Flutter
@ -76,6 +79,9 @@ PODS:
- mob_sharesdk/ShareSDKPlatforms/Line
- mob_sharesdk/ShareSDKPlatforms/WeChat_Lite
- mob_sharesdk/ShareSDKUI
- sqflite (0.0.3):
- Flutter
- FMDB (>= 2.7.5)
- SSZipArchive (2.4.3)
- tobias (0.0.1):
- Flutter
@ -111,11 +117,12 @@ DEPENDENCIES:
- image_pickers (from `.symlinks/plugins/image_pickers/ios`)
- number_precision (from `.symlinks/plugins/number_precision/ios`)
- package_info (from `.symlinks/plugins/package_info/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
- permission_handler (from `.symlinks/plugins/permission_handler/ios`)
- scan (from `.symlinks/plugins/scan/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
- sharesdk_plugin (from `.symlinks/plugins/sharesdk_plugin/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- SSZipArchive (~> 2.4.2)
- tobias (from `.symlinks/plugins/tobias/ios`)
- tpns_flutter_plugin (from `.symlinks/plugins/tpns_flutter_plugin/ios`)
@ -128,6 +135,7 @@ DEPENDENCIES:
SPEC REPOS:
https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git:
- AFNetworking
- FMDB
- mob_sharesdk
- MOBFoundation
- OpenWeChatSDK
@ -157,8 +165,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/number_precision/ios"
package_info:
:path: ".symlinks/plugins/package_info/ios"
path_provider:
:path: ".symlinks/plugins/path_provider/ios"
path_provider_ios:
:path: ".symlinks/plugins/path_provider_ios/ios"
permission_handler:
:path: ".symlinks/plugins/permission_handler/ios"
scan:
@ -167,6 +175,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/shared_preferences_foundation/ios"
sharesdk_plugin:
:path: ".symlinks/plugins/sharesdk_plugin/ios"
sqflite:
:path: ".symlinks/plugins/sqflite/ios"
tobias:
:path: ".symlinks/plugins/tobias/ios"
tpns_flutter_plugin:
@ -188,6 +198,7 @@ SPEC CHECKSUMS:
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_pdfview: 25f53dd6097661e6395b17de506e6060585946bd
fluwx: 79c66b6d795ab8208262ada215d9e60388cfe492
FMDB: 57486c1117fd8e0e6b947b2f54c3f42bf8e57a4e
geolocator: f5e3de65e241caba7ce3e8a618803387bda73384
image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb
image_pickers: 25c8916d358bc9d2707cb470ba3d57497f105773
@ -196,12 +207,13 @@ SPEC CHECKSUMS:
number_precision: 26fa2be2212f9d1429f92d667d6b0aa4df0058d8
OpenWeChatSDK: ea48e9db20645f78128db9091893910280b8e4b1
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0
scan: aea35bb4aa59ccc8839c576a18cd57c7d492cc86
SDWebImage: e5cc87bf736e60f49592f307bdf9e157189298a3
shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472
sharesdk_plugin: f29a6f471ae1c253e96636d62106c3f8d793948c
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
tobias: 2aded9b83e3663b907360a800d8e3c13284f25c5
TPNS-iOS: 36c335eff80670de6ede780ab827f679d78f64ff
@ -209,8 +221,8 @@ SPEC CHECKSUMS:
UMCommon: 47e0b53f6a36568e958a5abd005ed7577fcac9ad
UMDevice: 9ef8045b59e0479cff7062915c879a1af46fa094
umeng_common_sdk: a8abd7f86dfd013dbbeeae587ee143760c6582f2
url_launcher: a1c0cc845906122c4784c542523d8cacbded5626
video_player_avfoundation: 6d971a232d72e6ee25368378d48a079dea01f1cf
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
video_player_avfoundation: 81e49bb3d9fb63dccf9fa0f6d877dc3ddbeac126
wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f
webview_flutter: 5fb4def2bbd4339889ee14d045b605cefc5bc232
ZLPhotoBrowser-objc: c7657d3bc85ae231884e058d0e3638f619164736

15
ios/Runner.xcodeproj/project.pbxproj

@ -660,12 +660,7 @@
"-ObjC",
"-l\"c++\"",
"-l\"image_pickers\"",
"-l\"path_provider\"",
"-l\"permission_handler\"",
"-l\"sqlite3\"",
"-l\"wakelock\"",
"-l\"webview_flutter\"",
"-l\"z\"",
"-fcxx-modules",
"-fmodules",
"-ld64",
@ -864,12 +859,7 @@
"-ObjC",
"-l\"c++\"",
"-l\"image_pickers\"",
"-l\"path_provider\"",
"-l\"permission_handler\"",
"-l\"sqlite3\"",
"-l\"wakelock\"",
"-l\"webview_flutter\"",
"-l\"z\"",
"-fcxx-modules",
"-fmodules",
"-ld64",
@ -954,12 +944,7 @@
"-ObjC",
"-l\"c++\"",
"-l\"image_pickers\"",
"-l\"path_provider\"",
"-l\"permission_handler\"",
"-l\"sqlite3\"",
"-l\"wakelock\"",
"-l\"webview_flutter\"",
"-l\"z\"",
"-fcxx-modules",
"-fmodules",
"-ld64",

72
lib/im/Proto.dart

@ -0,0 +1,72 @@
import 'dart:typed_data';
/**
*
*
*
*
* 4 +body
* 2 header长度
* 2 1
* 4 15
* 4 1
* body 2048-16
* 2048
*/
class Proto {
static const int HEADER_LENGTH = 16; // 16
static const int VERSION = 1;
int operation;
int seqId;
Uint8List body;
Proto(this.operation, this.seqId, this.body);
Uint8List toBytes() {
final buffer = BytesBuilder();
buffer.add(_intToBytes(HEADER_LENGTH + body.length, 4));
buffer.add(_shortToBytes(HEADER_LENGTH, 2));
buffer.add(_shortToBytes(VERSION, 2));
buffer.add(_intToBytes(operation, 4));
buffer.add(_intToBytes(seqId, 4));
buffer.add(body);
return buffer.toBytes();
}
static Proto fromBytes(Uint8List data) {
final buffer = ByteData.sublistView(data);
int offset = 0;
int packetLen = buffer.getInt32(offset, Endian.big);
offset += 4;
int headerLen = buffer.getInt16(offset, Endian.big);
offset += 2;
int version = buffer.getInt16(offset, Endian.big);
offset += 2;
int operation = buffer.getInt32(offset, Endian.big);
offset += 4;
int seqId = buffer.getInt32(offset, Endian.big);
offset += 4;
Uint8List body = data.sublist(offset);
return Proto(operation, seqId, body);
}
List<int> _intToBytes(int value, int length) {
final bytes = ByteData(length);
bytes.setInt32(0, value, Endian.big);
return bytes.buffer.asUint8List();
}
List<int> _shortToBytes(int value, int length) {
final bytes = ByteData(length);
bytes.setInt16(0, value, Endian.big);
return bytes.buffer.asUint8List();
}
}

110
lib/im/SocketClient.dart

@ -0,0 +1,110 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:huixiang/im/Proto.dart';
import 'package:huixiang/im/database/message.dart';
import 'package:huixiang/im/out/auth.pb.dart';
import 'package:huixiang/im/out/message.pb.dart';
import 'package:huixiang/main.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SocketClient {
Socket _socket;
SharedPreferences shared;
connect() async {
shared = await SharedPreferences.getInstance();
await Socket.connect('192.168.10.129', 9090).then((value) {
debugPrint("socket-connect");
_socket = value;
_socket.listen((data) {
print(data);
print("socket-listen");
Proto proto = Proto.fromBytes(data);
MsgData data1 = MsgData.fromBuffer(proto.body);
print('收到来自:${data1.from},消息内容: ${utf8.decode(data1.data)} ');
hxDatabase.insert(createMessage(userId, utf8.decode(data1.data), msgType: data1.type.value, userId: data1.from));
callbacks.forEach((callback) {
callback.call(data1);
});
}, onError: (Object error, StackTrace stackTrace) {
debugPrint("socket-error: $error, stackTrace: ${stackTrace}");
});
authRequest(shared.getString("token"));
}).catchError((error) {
debugPrint("socket-connect-error: $error");
});
}
List<Function> callbacks = [];
addCallback(Function callback) {
callbacks.add(callback);
}
removeCallback(Function callback) {
callbacks.remove(callback);
}
dispose() {
_socket.close();
}
authRequest(String token) {
if (!checkSocket()) {
return;
}
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);
}
Future<Message> sendMessage(String toId, String content) async {
Map message = createMessage(toId, content, userId: userId);
int id = await hxDatabase.insert(message).catchError((error) {
debugPrint("insertMessage: $error");
});
if (!checkSocket()) {
hxDatabase.update({"id": id, "state": 3}).catchError((error) {
debugPrint("insertMessage: $error");
});
message["id"] = id;
message["state"] = 3;
return Message.fromJson(message);
}
message["id"] = id;
Uint8List data = utf8.encode(content);
MsgData msgData = MsgData(to: toId, from: userId, type: MsgType.SINGLE_TEXT, data: data);
final proto2 = Proto(5, 1, msgData.writeToBuffer());
_socket.add(proto2.toBytes());
debugPrint("sendMessage: ${message["id"]}");
return Message.fromJson(message);
}
checkSocket() {
if (_socket == null) {
connect();
return false;
}
return true;
}
get userId => shared.getString("userId");
}

728
lib/im/chat_details_page.dart

@ -7,10 +7,13 @@ 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/main.dart';
import 'package:huixiang/retrofit/retrofit_api.dart';
import 'package:huixiang/view_widget/my_appbar.dart';
import 'package:flutter/cupertino.dart';
import 'package:image_pickers/image_pickers.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../community/release_dynamic.dart';
import '../../generated/l10n.dart';
import '../../utils/font_weight.dart';
@ -57,6 +60,19 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
// SmartDialog.showToast("聊天 $txt", alignment: Alignment.center);
}
List<Message> messages = [];
loadMessageList() async {
selfUserId = (await SharedPreferences.getInstance()).getString("userId");
toUserId = widget.arguments["toId"];
messages = await hxDatabase.queryUList(toUserId);
if (mounted) setState(() {});
}
String selfUserId = "";
String toUserId = "";
@override
void initState() {
super.initState();
@ -64,20 +80,21 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
WidgetsBinding.instance.addObserver(this);
commentFocus.addListener(_focusNodeListener);
loadMessageList();
Future.delayed(Duration.zero, () {
jumpToBottom();
});
}
void jumpToBottom(){
scrollController.position
.jumpTo(scrollController.position.maxScrollExtent);
void jumpToBottom() {
scrollController.position.jumpTo(scrollController.position.maxScrollExtent);
}
void didChangeMetrics() {
WidgetsBinding.instance.addPostFrameCallback((_) {
isKeyBoardShow = MediaQuery.of(context).viewInsets.bottom > 0;
if (!mounted) return;
isKeyBoardShow = MediaQuery.of(context).viewInsets.bottom > 0;
if (MediaQuery.of(context).viewInsets.bottom == 0) {
if (isKeyBoardShow) {
FocusScope.of(context).requestFocus(FocusNode());
@ -211,7 +228,7 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
double h = MediaQuery.of(context).viewInsets.bottom;
if (h > 0) {
jumpToBottom();
if(keyboard < h){
if (keyboard < h) {
keyboard = h;
// setState(() {});
}
@ -240,7 +257,8 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
color: Colors.black,
size: 30,
),
)),
),
),
),
body: Container(
child: Column(
@ -262,7 +280,8 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
FocusScope.of(context).requestFocus(FocusNode());
});
},
child: chatDetailsList()),
child: chatDetailsList(),
),
],
),
),
@ -280,26 +299,32 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
return Container(
margin: EdgeInsets.only(bottom: 48.h),
child: ListView.builder(
itemCount: 10,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, position) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
setState((){
copyIndex = 0;
});
},
child: chatDetailsItem(),
);
}),
itemCount: messages.length,
shrinkWrap: true,
reverse: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, position) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
setState(() {
copyIndex = 0;
});
},
child: chatDetailsItem(messages[position]),
);
},
),
);
}
Widget chatDetailsItem() {
Widget chatDetailsItem(Message message) {
bool isSelf = message.fromId == selfUserId;
bool isText = message.msgType == 0;
return Container(
padding: EdgeInsets.only(top: 32.h,),
padding: EdgeInsets.only(
top: 32.h,
),
child: Column(
children: [
Text(
@ -311,7 +336,8 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
fontWeight: MyFontWeight.regular,
),
),
Padding(
if (messages.indexOf(message) == (messages.length - 1))
Padding(
padding: EdgeInsets.only(top: 10.h, bottom: 24.h),
child: Text(
"在对方未回复或关注你之前,你只能发送一条信息",
@ -323,175 +349,46 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
),
),
),
SizedBox(
height: 16.h,
),
if(copyIndex == 1)
Stack(
alignment: Alignment.bottomCenter,
children: [
Container(
padding: EdgeInsets.only(bottom:13.h),
child: Container(
width: 180.w,
decoration: BoxDecoration(
color: Color(0xFF2A2A2A),
borderRadius: BorderRadius.circular(6),
),
padding: EdgeInsets.symmetric(horizontal: 32.w,vertical: 7.5.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
GestureDetector(
onTap: (){
setState((){
copyIndex = 0;
this.copy(tex);
});
},
child:Column(
children: [
Image.asset(
"assets/image/icon_chat_copy.webp",
height:16,
width: 16,
),
SizedBox(height: 2.h,),
Text(
"复制",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 12.sp,
fontWeight: MyFontWeight.regular,
),
),
],
) ,
),
GestureDetector(
onTap: (){},
child: Column(
children: [
Image.asset(
"assets/image/icon_chat_delete.webp",
height:16,
width: 16,
),
SizedBox(height: 2.h,),
Text(
S.of(context).shanchu,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 12.sp,
fontWeight: MyFontWeight.regular,
),
),
],
),
)
],
),
),
),
Image.asset(
"assets/image/icon_copy_j.webp",
height: 17,
width: 17,
),
],
),
Padding(padding:EdgeInsets.only(left: 17.w,right: 39.w),
child: Row(
children: [
// MImage(
// "",
// isCircle: true,
// width: 44,
// height: 44,
// fit: BoxFit.cover,
// errorSrc: "assets/image/default_user.webp",
// fadeSrc: "assets/image/default_user.webp",
// ),
Image.asset(
"assets/image/fuka_zj.webp",
height: 44.h,
width: 44.h,
),
SizedBox(
width: 12.w,
),
Expanded(
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,
)
],
),
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 12.w),
child:GestureDetector(
onLongPress:(){
setState((){
copyIndex =1;
});
},
child:
Text(
tex = "上次你在我这里买的水果钱是不是忘记付了?一共18块钱做点生意也是真的不容易啊。",
textAlign: TextAlign.left,
style: TextStyle(
height: 1.2.h,
color: Color(0XFF0D0D0D),
fontSize: 17.sp,
fontWeight: MyFontWeight.medium,
),
),
)
)),
],
),),
SizedBox(height: 40.h,),
if(copyIndex == 1)
Stack(
if (messages.indexOf(message) == (messages.length - 1))
SizedBox(
height: 16.h,
),
if (copyIndex == 1)
Stack(
alignment: Alignment.bottomCenter,
children: [
Container(
padding: EdgeInsets.only(bottom:13.h),
padding: EdgeInsets.only(bottom: 13.h),
child: Container(
width: 180.w,
decoration: BoxDecoration(
color: Color(0xFF2A2A2A),
borderRadius: BorderRadius.circular(6),
),
padding: EdgeInsets.symmetric(horizontal: 32.w,vertical: 7.5.h),
padding: EdgeInsets.symmetric(
horizontal: 32.w, vertical: 7.5.h,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
GestureDetector(
onTap: (){
setState((){
onTap: () {
setState(() {
copyIndex = 0;
this.copy(tex);
});
},
child:Column(
child: Column(
children: [
Image.asset(
"assets/image/icon_chat_copy.webp",
height:16,
height: 16,
width: 16,
),
SizedBox(height: 2.h,),
SizedBox(
height: 2.h,
),
Text(
"复制",
textAlign: TextAlign.center,
@ -502,18 +399,20 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
),
),
],
) ,
),
),
GestureDetector(
onTap: (){},
onTap: () {},
child: Column(
children: [
Image.asset(
"assets/image/icon_chat_delete.webp",
height:16,
height: 16,
width: 16,
),
SizedBox(height: 2.h,),
SizedBox(
height: 2.h,
),
Text(
S.of(context).shanchu,
textAlign: TextAlign.center,
@ -537,127 +436,293 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
),
],
),
Padding(padding:EdgeInsets.only(left:36.w,right: 16.w),
/// not self
if (!isSelf && isText)
Padding(
padding: EdgeInsets.only(left: 17.w, right: 39.w),
child: Row(
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
color: Color(0xFFFF441A),
),
width: 20,
height: 20,
alignment: Alignment.center,
child: Text(
"!",
textAlign: TextAlign.left,
style: TextStyle(
color: Colors.white,
fontSize: 17.sp,
fontWeight: MyFontWeight.regular,
children: [
// MImage(
// "",
// isCircle: true,
// width: 44,
// height: 44,
// fit: BoxFit.cover,
// errorSrc: "assets/image/default_user.webp",
// fadeSrc: "assets/image/default_user.webp",
// ),
Image.asset(
"assets/image/fuka_zj.webp",
height: 44.h,
width: 44.h,
),
),
),
SizedBox(
width: 12.w,
SizedBox(
width: 12.w,
),
Expanded(
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,
)
],
),
padding: EdgeInsets.symmetric(
vertical: 8.h, horizontal: 12.w),
child: GestureDetector(
onLongPress: () {
setState(() {
copyIndex = 1;
});
},
child: Text(
tex = message.content,
textAlign: TextAlign.left,
style: TextStyle(
height: 1.2.h,
color: Color(0XFF0D0D0D),
fontSize: 17.sp,
fontWeight: MyFontWeight.medium,
),
),
))),
],
),
Expanded(
),
if (!isSelf && isText)
SizedBox(
height: 40.h,
),
if (copyIndex == 1)
Stack(
alignment: Alignment.bottomCenter,
children: [
Container(
padding: EdgeInsets.only(bottom: 13.h),
child: Container(
width: 180.w,
decoration: BoxDecoration(
color: Color(0xFF2A2A2A),
borderRadius: BorderRadius.circular(6),
color: Color(0xFF32A060),
),
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 12.w),
child: GestureDetector(
onLongPress:(){
setState((){
copyIndex = 1;
});
},
child:
Text(
tex = "凭本事买的为啥要给你钱啊伙计",
padding:
EdgeInsets.symmetric(horizontal: 32.w, vertical: 7.5.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
setState(() {
copyIndex = 0;
this.copy(tex);
});
},
child: Column(
children: [
Image.asset(
"assets/image/icon_chat_copy.webp",
height: 16,
width: 16,
),
SizedBox(
height: 2.h,
),
Text(
"复制",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 12.sp,
fontWeight: MyFontWeight.regular,
),
),
],
),
),
GestureDetector(
onTap: () {},
child: Column(
children: [
Image.asset(
"assets/image/icon_chat_delete.webp",
height: 16,
width: 16,
),
SizedBox(
height: 2.h,
),
Text(
S.of(context).shanchu,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 12.sp,
fontWeight: MyFontWeight.regular,
),
),
],
),
)
],
),
),
),
Image.asset(
"assets/image/icon_copy_j.webp",
height: 17,
width: 17,
),
],
),
/// self
if (isSelf && isText)
Padding(
padding: EdgeInsets.only(left: 36.w, right: 16.w),
child: Row(
children: [
if (message.state == 3)
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
color: Color(0xFFFF441A),
),
width: 20,
height: 20,
alignment: Alignment.center,
child: Text(
"!",
textAlign: TextAlign.left,
style: TextStyle(
height: 1.2.h,
color: Colors.white,
fontSize: 17.sp,
fontWeight: MyFontWeight.medium,
fontWeight: MyFontWeight.regular,
),
),
),
)),
SizedBox(
width: 12.w,
),
// MImage(
// "",
// isCircle: true,
// width: 44,
// height: 44,
// fit: BoxFit.cover,
// errorSrc: "assets/image/default_user.webp",
// fadeSrc: "assets/image/default_user.webp",
// ),
Image.asset(
"assets/image/fuka_zj.webp",
height: 44,
width: 44,
),
],
)),
Padding(padding:EdgeInsets.only(left: 17.w,right: 39.w,top: 20.h),
child: Row(
children: [
// MImage(
// "",
// isCircle: true,
// width: 44,
// height: 44,
// fit: BoxFit.cover,
// errorSrc: "assets/image/default_user.webp",
// fadeSrc: "assets/image/default_user.webp",
// ),
Image.asset(
"assets/image/fuka_zj.webp",
height: 44.h,
width: 44.h,
),
SizedBox(
width: 12.w,
),
Expanded(
flex: 3,
if (message.state == 3)
SizedBox(
width: 12.w,
),
Expanded(
child: Container(
alignment: Alignment.centerRight,
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,
)
],
color: Color(0xFF32A060),
),
child:GestureDetector(
onLongPress:(){
setState((){
padding:
EdgeInsets.symmetric(vertical: 8.h, horizontal: 12.w),
child: GestureDetector(
onLongPress: () {
setState(() {
copyIndex = 1;
});
},
child: Image.asset(
"assets/image/icon_guide_4.webp",
width:180.h,
height: 200.h,
fit: BoxFit.fill,
child: Text(
tex = message.content,
textAlign: TextAlign.left,
style: TextStyle(
height: 1.2.h,
color: Colors.white,
fontSize: 17.sp,
fontWeight: MyFontWeight.medium,
),
),
)
)),
Expanded(flex:1,child: Container(),)
],
),),
Padding(
),
),
),
),
SizedBox(
width: 12.w,
),
// MImage(
// "",
// isCircle: true,
// width: 44,
// height: 44,
// fit: BoxFit.cover,
// errorSrc: "assets/image/default_user.webp",
// fadeSrc: "assets/image/default_user.webp",
// ),
Image.asset(
"assets/image/fuka_zj.webp",
height: 44,
width: 44,
),
],
),
),
/// not self image
if (!isSelf && !isText)
Padding(
padding: EdgeInsets.only(left: 17.w, right: 39.w, top: 20.h),
child: Row(
children: [
// MImage(
// "",
// isCircle: true,
// width: 44,
// height: 44,
// fit: BoxFit.cover,
// errorSrc: "assets/image/default_user.webp",
// fadeSrc: "assets/image/default_user.webp",
// ),
Image.asset(
"assets/image/fuka_zj.webp",
height: 44.h,
width: 44.h,
),
SizedBox(
width: 12.w,
),
Expanded(
flex: 3,
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.asset(
"assets/image/icon_guide_4.webp",
width: 180.h,
height: 200.h,
fit: BoxFit.fill,
),
))),
Expanded(
flex: 1,
child: Container(),
)
],
),
),
/// no reply long time
if (messages.indexOf(message) == 0)
Padding(
padding: EdgeInsets.only(left: 17.w, right: 17.w, top: 24.h),
child: Text(
"由于对方没有回复你,你只能发送一条消息,需要对方关注或回复后才能恢复正常聊天",
@ -678,7 +743,7 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
Widget input() {
return Container(
color: Color(0xFFFDFCFC),
padding: EdgeInsets.only(top:14.h, bottom: 15.h),
padding: EdgeInsets.only(top: 14.h, bottom: 15.h),
child: Column(
children: [
///
@ -695,7 +760,7 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
borderRadius: BorderRadius.circular(6),
),
child: Container(
margin: EdgeInsets.only(left:17.w),
margin: EdgeInsets.only(left: 17.w),
alignment: Alignment.topLeft,
child: TextField(
textInputAction: TextInputAction.send,
@ -708,6 +773,13 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
if (commentText.trim() == "") {
return;
}
socketClient.sendMessage(toUserId, commentText).then((value) {
Message message = value;
messages.insert(0, message);
chatController.clear();
if (mounted)
setState(() {});
});
// widget.queryMemberComment(commentText);
},
maxLines: 8,
@ -817,7 +889,7 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
width: double.infinity,
height: 1.h,
color: Color(0xFFF7F7F7),
margin:EdgeInsets.only(bottom:10.h),
margin: EdgeInsets.only(bottom: 10.h),
),
Row(
children: [
@ -841,7 +913,7 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
)
],
),
margin:EdgeInsets.only(right: 15.w,left: 14.w),
margin: EdgeInsets.only(right: 15.w, left: 14.w),
padding: EdgeInsets.all(12),
child: Image.asset(
"assets/image/icon_chat_camera.webp",
@ -849,53 +921,60 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
width: 24,
),
),
Padding(padding:EdgeInsets.only(top: 8.h),
child: Text(
"拍照",
style: TextStyle(
fontSize:12.sp, color: Color(0xFFA29E9E),
fontWeight: MyFontWeight.regular,),
),),
Padding(
padding: EdgeInsets.only(top: 8.h),
child: Text(
"拍照",
style: TextStyle(
fontSize: 12.sp,
color: Color(0xFFA29E9E),
fontWeight: MyFontWeight.regular,
),
),
),
],
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
getImageOrVideo(GalleryMode.image);
},
child: Column(
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: Color(0xFFFFFFFF),
boxShadow: [
BoxShadow(
color: Color(0xFFD5D5D5).withAlpha(25),
offset: Offset(4, 2),
blurRadius: 4,
spreadRadius: 0,
)
],
behavior: HitTestBehavior.opaque,
onTap: () {
getImageOrVideo(GalleryMode.image);
},
child: Column(
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: Color(0xFFFFFFFF),
boxShadow: [
BoxShadow(
color: Color(0xFFD5D5D5).withAlpha(25),
offset: Offset(4, 2),
blurRadius: 4,
spreadRadius: 0,
)
],
),
padding: EdgeInsets.all(12),
child: Image.asset(
"assets/image/icon_chat_photo.webp",
height: 24,
width: 24,
),
),
padding: EdgeInsets.all(12),
child: Image.asset(
"assets/image/icon_chat_photo.webp",
height: 24,
width: 24,
Padding(
padding: EdgeInsets.only(top: 8.h),
child: Text(
"相册",
style: TextStyle(
fontSize: 12.sp,
color: Color(0xFFA29E9E),
fontWeight: MyFontWeight.regular,
),
),
),
),
Padding(padding:EdgeInsets.only(top: 8.h),
child: Text(
"相册",
style: TextStyle(
fontSize:12.sp, color: Color(0xFFA29E9E),
fontWeight: MyFontWeight.regular,),
),),
],
)
),
],
)),
],
)
],
@ -907,14 +986,17 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
);
}
showCustomDialog(BuildContext context,int position ){
showCustomDialog(BuildContext context, int position) {
showDialog(
context: context,
builder: (BuildContext context) {
return new AlertDialog(
backgroundColor: Color(0xFF2A2A2A),
elevation: 0,
contentPadding:EdgeInsets.only(top: 8.h,bottom: 5.h,),
contentPadding: EdgeInsets.only(
top: 8.h,
bottom: 5.h,
),
content: Container(
height: 40.h,
// width:20.w,
@ -927,7 +1009,7 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
children: [
Image.asset(
"assets/image/icon_chat_copy.webp",
height:16,
height: 16,
width: 16,
),
Text(
@ -945,7 +1027,7 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
children: [
Image.asset(
"assets/image/icon_chat_delete.webp",
height:16,
height: 16,
width: 16,
),
Text(

123
lib/im/database/hx_database.dart

@ -0,0 +1,123 @@
import 'package:flutter/cupertino.dart';
import 'package:huixiang/im/database/message.dart';
import 'package:huixiang/im/database/migration.dart';
import 'package:sqflite/sqflite.dart';
class HxDatabase {
Database db;
void open() async {
// _migrations.add(Migration(1, 2, (Database database) async {
// database.execute('ALTER TABLE `Message` ADD COLUMN `replyId` VARCHAR(20) DEFAULT NULL AFTER `toId`');
// }));
await openDatabase(
'hx.db',
version: 2,
onCreate: (Database db, int version) async {
db.execute('CREATE TABLE IF NOT EXISTS `Message` (`id` INTEGER, `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`))');
},
onConfigure: (database) async {
await database.execute('PRAGMA foreign_keys = ON');
},
onUpgrade: (database, startVersion, endVersion) async {
await runMigrations(database, startVersion, endVersion, _migrations);
},
onOpen: (Database db) {
this.db = db;
}
);
}
void close() {
db.close();
}
Future<List<Message>> queryList(userId) {
if (db == null) {
return Future.value(<Message>[]);
}
String sql = 'SELECT * FROM Message WHERE toId = ? OR fromId = ? GROUP BY toId,fromId ORDER BY time DESC';
return db.rawQuery(sql, [userId, userId]).then((value) {
return value.map((e) {
debugPrint("Message: ${e}");
return Message.fromJson(e);
}).toList();
}, onError: (error) {
debugPrint("Messageerror: $error");
});
}
Future<List<Message>> queryUList(userId) {
if (db == null) {
return Future.value(<Message>[]);
}
String sql = 'SELECT * FROM Message WHERE toId = ? OR fromId = ? ORDER BY time DESC';
return db.rawQuery(sql, [userId, userId]).then((value) {
return value.map((e) => Message.fromJson(e)).toList();
}, onError: (error) {
debugPrint("Messageerror: $error");
});
}
Future<List<Map>> queryListAll() {
if (db == null) {
return Future.value();
}
String sql = 'SELECT * FROM Message ORDER BY time DESC';
return db.rawQuery(sql);
}
Future<int> deleteAll() async {
return db.delete("Message");
}
update(Map<dynamic, dynamic> message) {
}
Future<int> insert(Map message) async {
if (db == null) {
return Future.value(0);
}
debugPrint("Messageinsert: ${message}");
return db.insert("Message", message);
}
final List<Migration> _migrations = [];
addMigrations(List<Migration> migrations) {
_migrations.addAll(migrations);
return this;
}
Future<void> runMigrations(
final Database migrationDatabase,
final int startVersion,
final int endVersion,
final List<Migration> migrations,
) async {
final relevantMigrations = migrations
.where((migration) => migration.startVersion >= startVersion)
.toList()
..sort(
(first, second) => first.startVersion.compareTo(second.startVersion));
if (relevantMigrations.isEmpty ||
relevantMigrations.last.endVersion != endVersion) {
throw StateError(
'There is no migration supplied to update the database to the current version.'
' Aborting the migration.',
);
}
for (final migration in relevantMigrations) {
await migration.migrate(migrationDatabase);
}
}
}

146
lib/im/database/hx_database.g.dart

@ -0,0 +1,146 @@
// // GENERATED CODE - DO NOT MODIFY BY HAND
//
// part of 'hx_database.dart';
//
// // **************************************************************************
// // FloorGenerator
// // **************************************************************************
//
// // ignore: avoid_classes_with_only_static_members
// import 'package:floor/floor.dart';
//
// class $FloorHxDatabase {
// /// Creates a database builder for a persistent database.
// /// Once a database is built, you should keep a reference to it and re-use it.
// static _$HxDatabaseBuilder databaseBuilder(String name) =>
// _$HxDatabaseBuilder(name);
//
// /// Creates a database builder for an in memory database.
// /// Information stored in an in memory database disappears when the process is killed.
// /// Once a database is built, you should keep a reference to it and re-use it.
// static _$HxDatabaseBuilder inMemoryDatabaseBuilder() =>
// _$HxDatabaseBuilder(null);
// }
//
// class _$HxDatabaseBuilder {
// _$HxDatabaseBuilder(this.name);
//
// final String name;
//
// final List<Migration> _migrations = [];
//
// Callback _callback;
//
// /// Adds migrations to the builder.
// _$HxDatabaseBuilder addMigrations(List<Migration> migrations) {
// _migrations.addAll(migrations);
// return this;
// }
//
// /// Adds a database [Callback] to the builder.
// _$HxDatabaseBuilder addCallback(Callback callback) {
// _callback = callback;
// return this;
// }
//
// /// Creates the database and initializes it.
// Future<HxDatabase> build() async {
// final path = name != null
// ? await sqfliteDatabaseFactory.getDatabasePath(name)
// : ':memory:';
// final database = _$HxDatabase();
// database.database = await database.open(
// path,
// _migrations,
// _callback,
// );
// return database;
// }
// }
//
// class _$HxDatabase extends HxDatabase {
// _$HxDatabase([StreamController<String> listener]) {
// changeListener = listener ?? StreamController<String>.broadcast();
// }
//
// MessageDao _messageDaoInstance;
//
// Future<sqflite.Database> open(
// String path,
// List<Migration> migrations, [
// Callback callback,
// ]) async {
// final databaseOptions = sqflite.OpenDatabaseOptions(
// version: 1,
// onConfigure: (database) async {
// await database.execute('PRAGMA foreign_keys = ON');
// await callback?.onConfigure?.call(database);
// },
// onOpen: (database) async {
// await callback?.onOpen?.call(database);
// },
// onUpgrade: (database, startVersion, endVersion) async {
// await MigrationAdapter.runMigrations(
// database, startVersion, endVersion, migrations);
//
// await callback?.onUpgrade?.call(database, startVersion, endVersion);
// },
// onCreate: (database, version) async {
// await database.execute(
// 'CREATE TABLE IF NOT EXISTS `Message` (`id` INTEGER, `fromId` INTEGER, `toId` INTEGER, `content` TEXT, `attach` TEXT, `msgType` INTEGER, `time` INTEGER, `state` INTEGER, `isDelete` INTEGER, PRIMARY KEY (`id`))');
//
// await callback?.onCreate?.call(database, version);
// },
// );
// return sqfliteDatabaseFactory.openDatabase(path, options: databaseOptions);
// }
//
// @override
// MessageDao get messageDao {
// return _messageDaoInstance ??= _$MessageDao(database, changeListener);
// }
// }
//
// class _$MessageDao extends MessageDao {
// _$MessageDao(
// this.database,
// this.changeListener,
// ) : _queryAdapter = QueryAdapter(database, changeListener),
// _messageInsertionAdapter = InsertionAdapter(
// database,
// 'Message',
// (Message item) => item.toJson(),
// changeListener);
//
// final sqflite.DatabaseExecutor database;
//
// final StreamController<String> changeListener;
//
// final QueryAdapter _queryAdapter;
//
// final InsertionAdapter<Message> _messageInsertionAdapter;
//
// @override
// Stream<List<Message>> findMessageByToId(int toId) {
// return _queryAdapter.queryListStream(
// 'SELECT * FROM Message WHERE toId = ?1',
// mapper: (Map<String, Object> row) => Message.fromJson(row),
// arguments: [toId],
// queryableName: 'Message',
// isView: false);
// }
//
// @override
// Future<List<Message>> findMessageByGroup(int userId) {
// debugPrint("findMessageByGroup: $userId");
// return _queryAdapter.queryList(
// 'SELECT * FROM Message WHERE toId = ?1 OR fromId = ?2 GROUP BY toId,fromId ORDER BY time DESC',
// mapper: (Map<String, Object> row) => Message.fromJson(row),
// arguments: [userId, userId]);
// }
//
// @override
// Future<void> insertMessage(Message message) async {
// await _messageInsertionAdapter.insert(message, OnConflictStrategy.abort);
// }
// }

63
lib/im/database/message.dart

@ -0,0 +1,63 @@
class Message {
int id;
String fromId;
String toId;
String replyId;
String content;
String attach;
int msgType;
String time;
int state;
int isDelete;
Message(this.id, this.fromId, this.toId, this.replyId, this.content, this.attach, this.msgType, this.time, this.state, this.isDelete);
factory Message.fromJson(Map<String, dynamic> json) => Message(
json["id"],
json["fromId"],
json["toId"],
json["replyId"],
json["content"],
json["attach"],
json["msgType"],
json["time"],
json["state"],
json["isDelete"]);
Map<String, dynamic> toJson() => <String, dynamic>{
"id": id,
"fromId": fromId,
"toId": toId,
"replyId": replyId,
"content": content,
"attach": attach,
"msgType": msgType,
"time": time,
"state": state,
"isDelete": isDelete == null ? 0 : isDelete
};
}
createMessage(var toId, String content, {String attach, int msgType, userId, replyId}) {
return <String, dynamic>{
"fromId": userId,
"toId": toId,
"replyId": replyId,
"content": content,
"attach": attach,
"msgType": msgType ?? 0,
"time": "${DateTime.now().millisecondsSinceEpoch}",
"state": 0,
"isDelete": 0
};
}

17
lib/im/database/message_dao.dart

@ -0,0 +1,17 @@
// import 'package:floor/floor.dart';
// import 'package:huixiang/im/database/message.dart';
//
//
// @dao
// abstract class MessageDao {
//
// @Query('SELECT * FROM Message WHERE toId = :toId')
// Stream<List<Message>> findMessageByToId(int toId);
//
// @insert
// Future<void> insertMessage(Message message);
//
// @Query('SELECT * FROM Message WHERE toId = :userId OR fromId = :userId GROUP BY toId,fromId ORDER BY time DESC')
// Future<List<Message>> findMessageByGroup(int userId);
//
// }

41
lib/im/database/migration.dart

@ -0,0 +1,41 @@
import 'package:sqflite/sqflite.dart' as sqflite;
/// Base class for a database migration.
///
/// Each migration can move between 2 versions that are defined by
/// [startVersion] and [endVersion].
class Migration {
/// The start version of the database.
final int startVersion;
/// The start version of the database.
final int endVersion;
/// Function that performs the migration.
final Future<void> Function(sqflite.Database database) migrate;
/// Creates a new migration between [startVersion] and [endVersion].
/// [migrate] will be called by the database and performs the actual
/// migration.
Migration(this.startVersion, this.endVersion, this.migrate)
: assert(startVersion > 0),
assert(startVersion < endVersion);
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is Migration &&
runtimeType == other.runtimeType &&
startVersion == other.startVersion &&
endVersion == other.endVersion &&
migrate == other.migrate;
@override
int get hashCode =>
startVersion.hashCode ^ endVersion.hashCode ^ migrate.hashCode;
@override
String toString() {
return 'Migration{startVersion: $startVersion, endVersion: $endVersion, migrate: $migrate}';
}
}

294
lib/im/im_view/im_page.dart

@ -1,9 +1,12 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:huixiang/generated/l10n.dart';
import 'package:huixiang/im/database/message.dart';
import 'package:huixiang/main.dart';
import 'package:huixiang/retrofit/data/base_data.dart';
import 'package:huixiang/retrofit/data/message.dart';
import 'package:huixiang/retrofit/data/msg_stats.dart';
import 'package:huixiang/retrofit/data/page.dart';
import 'package:huixiang/retrofit/retrofit_api.dart';
@ -18,8 +21,8 @@ import 'on_chat_message.dart';
import 'on_chat_msg_instance.dart';
class IMPage extends StatefulWidget {
IMPage(Key key) : super(key: key);
IMPage(Key key): super(key: key);
@override
State<StatefulWidget> createState() {
return _IMPage();
@ -42,7 +45,7 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
final TextEditingController imEditingController = TextEditingController();
@override
void onMessage(txt){
void onMessage(txt) {
// SmartDialog.showToast("列表 $txt", alignment: Alignment.center);
}
@ -57,57 +60,78 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
super.initState();
OnChatMsgInstance.instance.onChatMessage = this;
loadMessageList();
SharedPreferences.getInstance().then((value) {
apiService =
ApiService(Dio(), token: value.getString("token"), context: context);
queryMessage();
queryMsgStats();
});
}
_refresh() {
pageNum = 1;
queryMessage();
loadMessageList();
queryMsgStats();
}
queryMessage() async {
BaseData<PageInfo<Message>> baseData = await apiService.msgList({
"pageNum": pageNum,
"pageSize": 10,
"searchKey": "",
"state": "",
"typed": ""
}).catchError((onError) {
_refreshController.loadFailed();
_refreshController.refreshFailed();
});
List<String> userIds = [];
if (baseData != null && baseData.isSuccess) {
if (pageNum == 1) {
messages.clear();
}
List<Message> message = [];
message.addAll(baseData.data.list);
message.forEach((element) {
if (element.typed == 2 || element.typed == 3) {
messages.add(element);
}
});
_refreshController.loadComplete();
_refreshController.refreshCompleted();
if (mounted) setState(() {});
if (pageNum * 10 > int.tryParse(baseData.data.total)) {
_refreshController.loadNoData();
} else {
pageNum += 1;
}
} else {
_refreshController.loadFailed();
_refreshController.refreshFailed();
Stream streamSubscription ;
loadMessageList() async {
SharedPreferences shared = await SharedPreferences.getInstance();
String userId = shared.getString("userId");
messages = await hxDatabase.queryList(userId);
messages.forEach((element) {
debugPrint("messages: ${element.toJson()}");
});
userIds = messages
.map((e) => e.toId != userId ? e.toId : e.fromId)
.toSet().where((element) => element != userId)
.toList();
if (mounted) {
setState(() {});
}
}
// queryMessage() async {
// BaseData<PageInfo<Message>> baseData = await apiService.msgList({
// "pageNum": pageNum,
// "pageSize": 10,
// "searchKey": "",
// "state": "",
// "typed": ""
// }).catchError((onError) {
// _refreshController.loadFailed();
// _refreshController.refreshFailed();
// });
//
// if (baseData != null && baseData.isSuccess) {
// if (pageNum == 1) {
// messages.clear();
// }
// List<Message> message = [];
// message.addAll(baseData.data.list);
// message.forEach((element) {
// if (element.typed == 2 || element.typed == 3) {
// messages.add(element);
// }
// });
// _refreshController.loadComplete();
// _refreshController.refreshCompleted();
// if (mounted) setState(() {});
// if (pageNum * 10 > int.tryParse(baseData.data.total)) {
// _refreshController.loadNoData();
// } else {
// pageNum += 1;
// }
// } else {
// _refreshController.loadFailed();
// _refreshController.refreshFailed();
// }
// }
queryMsgStats() async {
if (apiService == null) {
SharedPreferences value = await SharedPreferences.getInstance();
@ -164,20 +188,16 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
// color: Colors.white,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFFD9FFDE),
Color(0xFFD9FFDE),
Color(0xFFFFFFFF),
Color(0xFFFFFFFF),
],
stops: [
0,
0.2,
0.4,
1
]),
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFFD9FFDE),
Color(0xFFD9FFDE),
Color(0xFFFFFFFF),
Color(0xFFFFFFFF),
],
stops: [0, 0.2, 0.4, 1],
),
),
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
@ -188,24 +208,28 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
Container(
padding: EdgeInsets.only(
top: MediaQuery.of(context).padding.top + 12.h,
bottom: 15.h,right: 16.w,left: 16.w),
bottom: 15.h,
right: 16.w,
left: 16.w),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Text(
S.of(context).xiaoxi,
style: TextStyle(
color: Colors.black,
fontSize: 18.sp,
fontWeight: MyFontWeight.bold,
),
)),
child: Text(
S.of(context).xiaoxi,
style: TextStyle(
color: Colors.black,
fontSize: 18.sp,
fontWeight: MyFontWeight.bold,
),
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).pushNamed('/router/chat_friend_group');
Navigator.of(context)
.pushNamed('/router/chat_friend_group');
},
child: Container(
padding: EdgeInsets.all(12),
@ -216,7 +240,8 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
child: Image.asset(
"assets/image/friend_grouping.webp",
fit: BoxFit.fill,
height: 14.h,width: 14.h,
height: 14.h,
width: 14.h,
),
),
),
@ -239,7 +264,7 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
Widget imSearchItem() {
return Container(
margin: EdgeInsets.fromLTRB(16.w, 0, 16.w, 0),
padding: EdgeInsets.symmetric(vertical:13.h),
padding: EdgeInsets.symmetric(vertical: 13.h),
decoration: BoxDecoration(
color: Color(0xFFFFFFFF),
borderRadius: BorderRadius.circular(4),
@ -285,29 +310,35 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
}
///
Widget chatList(){
Widget chatList() {
return Container(
child: ListView.builder(
padding: EdgeInsets.only(top: 16),
itemCount: 6,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, position) {
return GestureDetector(
behavior:HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).pushNamed('/router/chat_details_page');
},
child: chatItem(),
);
}),
padding: EdgeInsets.only(top: 16),
itemCount: userIds.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, position) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).pushNamed(
'/router/chat_details_page',
arguments: {
"toId": userIds[position],
},
);
},
child: chatItem(userIds[position]),
);
},
),
);
}
Widget chatItem(){
Widget chatItem(userId) {
return Container(
padding: EdgeInsets.only(left: 16.w,right: 17.w,bottom:18.h),
child: Row(
padding: EdgeInsets.only(left: 16.w, right: 17.w, bottom: 18.h),
child: Row(
children: [
// MImage(
// "",
@ -320,49 +351,58 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
// ),
Image.asset(
"assets/image/fuka_zj.webp",
height:54.h,
width:54.h,
height: 54.h,
width: 54.h,
),
SizedBox(width: 12.w,),
Expanded(child:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(child: Text(
"喽哈",
overflow: TextOverflow.ellipsis,
maxLines: 1,
SizedBox(
width: 12.w,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
"喽哈 $userId",
overflow: TextOverflow.fade,
maxLines: 1,
style: TextStyle(
fontSize: 16.sp,
color: Color(0xFF060606),
fontWeight: MyFontWeight.semi_bold,
),
),
),
Text(
"2021.03.08 13:22",
style: TextStyle(
fontSize: 16.sp,
color: Color(0xFF060606),
fontWeight: MyFontWeight.semi_bold,
)),),
Text(
"2021.03.08 13:22",
style: TextStyle(
fontSize: 12.sp,
color: Color(0xFFA29E9E),
fontWeight: MyFontWeight.regular,
fontSize: 12.sp,
color: Color(0xFFA29E9E),
fontWeight: MyFontWeight.regular,
),
),
),
],
),
SizedBox(height: 7.h,),
Row(
children: [
Expanded(child:Text(
"新开的火锅店好吃得很",
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 12.sp,
color: Color(0xFF353535),
fontWeight: MyFontWeight.regular,
],
),
SizedBox(
height: 7.h,
),
Row(
children: [
Expanded(
child: Text(
"新开的火锅店好吃得很",
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 12.sp,
color: Color(0xFF353535),
fontWeight: MyFontWeight.regular,
),
),
),
)),
Container(
Container(
width: 16,
height: 16,
decoration: BoxDecoration(
@ -370,17 +410,19 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
color: Color(0xFFFF441A),
),
child: RoundButton(
text:"99",
text: "99",
textColor: Colors.white,
fontWeight: MyFontWeight.regular,
backgroup: Color(0xFFFF441A),
fontSize: 10.sp,
radius: 100,
))
],
)
],
)),
),
),
],
),
],
),
),
],
),
);

160
lib/im/out/auth.pb.dart

@ -0,0 +1,160 @@
//
// Generated code. Do not modify.
// source: auth.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
class AuthReq extends $pb.GeneratedMessage {
factory AuthReq({
$core.String? uid,
$core.String? token,
}) {
final $result = create();
if (uid != null) {
$result.uid = uid;
}
if (token != null) {
$result.token = token;
}
return $result;
}
AuthReq._() : super();
factory AuthReq.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory AuthReq.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'AuthReq', createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'uid')
..aOS(2, _omitFieldNames ? '' : 'token')
..hasRequiredFields = false
;
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
AuthReq clone() => AuthReq()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
AuthReq copyWith(void Function(AuthReq) updates) => super.copyWith((message) => updates(message as AuthReq)) as AuthReq;
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static AuthReq create() => AuthReq._();
AuthReq createEmptyInstance() => create();
static $pb.PbList<AuthReq> createRepeated() => $pb.PbList<AuthReq>();
@$core.pragma('dart2js:noInline')
static AuthReq getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<AuthReq>(create);
static AuthReq? _defaultInstance;
@$pb.TagNumber(1)
$core.String get uid => $_getSZ(0);
@$pb.TagNumber(1)
set uid($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasUid() => $_has(0);
@$pb.TagNumber(1)
void clearUid() => clearField(1);
@$pb.TagNumber(2)
$core.String get token => $_getSZ(1);
@$pb.TagNumber(2)
set token($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2)
$core.bool hasToken() => $_has(1);
@$pb.TagNumber(2)
void clearToken() => clearField(2);
}
class AuthResp extends $pb.GeneratedMessage {
factory AuthResp({
$core.String? uid,
$core.int? code,
$core.String? message,
}) {
final $result = create();
if (uid != null) {
$result.uid = uid;
}
if (code != null) {
$result.code = code;
}
if (message != null) {
$result.message = message;
}
return $result;
}
AuthResp._() : super();
factory AuthResp.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory AuthResp.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'AuthResp', createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'uid')
..a<$core.int>(2, _omitFieldNames ? '' : 'code', $pb.PbFieldType.OU3)
..aOS(3, _omitFieldNames ? '' : 'message')
..hasRequiredFields = false
;
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
AuthResp clone() => AuthResp()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
AuthResp copyWith(void Function(AuthResp) updates) => super.copyWith((message) => updates(message as AuthResp)) as AuthResp;
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static AuthResp create() => AuthResp._();
AuthResp createEmptyInstance() => create();
static $pb.PbList<AuthResp> createRepeated() => $pb.PbList<AuthResp>();
@$core.pragma('dart2js:noInline')
static AuthResp getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<AuthResp>(create);
static AuthResp? _defaultInstance;
@$pb.TagNumber(1)
$core.String get uid => $_getSZ(0);
@$pb.TagNumber(1)
set uid($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasUid() => $_has(0);
@$pb.TagNumber(1)
void clearUid() => clearField(1);
@$pb.TagNumber(2)
$core.int get code => $_getIZ(1);
@$pb.TagNumber(2)
set code($core.int v) { $_setUnsignedInt32(1, v); }
@$pb.TagNumber(2)
$core.bool hasCode() => $_has(1);
@$pb.TagNumber(2)
void clearCode() => clearField(2);
@$pb.TagNumber(3)
$core.String get message => $_getSZ(2);
@$pb.TagNumber(3)
set message($core.String v) { $_setString(2, v); }
@$pb.TagNumber(3)
$core.bool hasMessage() => $_has(2);
@$pb.TagNumber(3)
void clearMessage() => clearField(3);
}
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');

11
lib/im/out/auth.pbenum.dart

@ -0,0 +1,11 @@
//
// Generated code. Do not modify.
// source: auth.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import

43
lib/im/out/auth.pbjson.dart

@ -0,0 +1,43 @@
//
// Generated code. Do not modify.
// source: auth.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
import 'dart:typed_data' as $typed_data;
@$core.Deprecated('Use authReqDescriptor instead')
const AuthReq$json = {
'1': 'AuthReq',
'2': [
{'1': 'uid', '3': 1, '4': 1, '5': 9, '10': 'uid'},
{'1': 'token', '3': 2, '4': 1, '5': 9, '10': 'token'},
],
};
/// Descriptor for `AuthReq`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List authReqDescriptor = $convert.base64Decode(
'CgdBdXRoUmVxEhAKA3VpZBgBIAEoCVIDdWlkEhQKBXRva2VuGAIgASgJUgV0b2tlbg==');
@$core.Deprecated('Use authRespDescriptor instead')
const AuthResp$json = {
'1': 'AuthResp',
'2': [
{'1': 'uid', '3': 1, '4': 1, '5': 9, '10': 'uid'},
{'1': 'code', '3': 2, '4': 1, '5': 13, '10': 'code'},
{'1': 'message', '3': 3, '4': 1, '5': 9, '10': 'message'},
],
};
/// Descriptor for `AuthResp`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List authRespDescriptor = $convert.base64Decode(
'CghBdXRoUmVzcBIQCgN1aWQYASABKAlSA3VpZBISCgRjb2RlGAIgASgNUgRjb2RlEhgKB21lc3'
'NhZ2UYAyABKAlSB21lc3NhZ2U=');

14
lib/im/out/auth.pbserver.dart

@ -0,0 +1,14 @@
//
// Generated code. Do not modify.
// source: auth.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
export 'auth.pb.dart';

272
lib/im/out/message.pb.dart

@ -0,0 +1,272 @@
//
// Generated code. Do not modify.
// source: message.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
import 'message.pbenum.dart';
export 'message.pbenum.dart';
class MsgData extends $pb.GeneratedMessage {
factory MsgData({
$core.String? to,
$core.String? from,
$core.int? ctime,
MsgType? type,
$core.List<$core.int>? data,
}) {
final $result = create();
if (to != null) {
$result.to = to;
}
if (from != null) {
$result.from = from;
}
if (ctime != null) {
$result.ctime = ctime;
}
if (type != null) {
$result.type = type;
}
if (data != null) {
$result.data = data;
}
return $result;
}
MsgData._() : super();
factory MsgData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory MsgData.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'MsgData', createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'to')
..aOS(2, _omitFieldNames ? '' : 'from')
..a<$core.int>(3, _omitFieldNames ? '' : 'ctime', $pb.PbFieldType.OU3)
..e<MsgType>(4, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OE, defaultOrMaker: MsgType.SINGLE_TEXT, valueOf: MsgType.valueOf, enumValues: MsgType.values)
..a<$core.List<$core.int>>(5, _omitFieldNames ? '' : 'data', $pb.PbFieldType.OY)
..hasRequiredFields = false
;
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
MsgData clone() => MsgData()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
MsgData copyWith(void Function(MsgData) updates) => super.copyWith((message) => updates(message as MsgData)) as MsgData;
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static MsgData create() => MsgData._();
MsgData createEmptyInstance() => create();
static $pb.PbList<MsgData> createRepeated() => $pb.PbList<MsgData>();
@$core.pragma('dart2js:noInline')
static MsgData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<MsgData>(create);
static MsgData? _defaultInstance;
@$pb.TagNumber(1)
$core.String get to => $_getSZ(0);
@$pb.TagNumber(1)
set to($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasTo() => $_has(0);
@$pb.TagNumber(1)
void clearTo() => clearField(1);
@$pb.TagNumber(2)
$core.String get from => $_getSZ(1);
@$pb.TagNumber(2)
set from($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2)
$core.bool hasFrom() => $_has(1);
@$pb.TagNumber(2)
void clearFrom() => clearField(2);
@$pb.TagNumber(3)
$core.int get ctime => $_getIZ(2);
@$pb.TagNumber(3)
set ctime($core.int v) { $_setUnsignedInt32(2, v); }
@$pb.TagNumber(3)
$core.bool hasCtime() => $_has(2);
@$pb.TagNumber(3)
void clearCtime() => clearField(3);
@$pb.TagNumber(4)
MsgType get type => $_getN(3);
@$pb.TagNumber(4)
set type(MsgType v) { setField(4, v); }
@$pb.TagNumber(4)
$core.bool hasType() => $_has(3);
@$pb.TagNumber(4)
void clearType() => clearField(4);
@$pb.TagNumber(5)
$core.List<$core.int> get data => $_getN(4);
@$pb.TagNumber(5)
set data($core.List<$core.int> v) { $_setBytes(4, v); }
@$pb.TagNumber(5)
$core.bool hasData() => $_has(4);
@$pb.TagNumber(5)
void clearData() => clearField(5);
}
class MsgNotify extends $pb.GeneratedMessage {
factory MsgNotify({
$core.int? seq,
}) {
final $result = create();
if (seq != null) {
$result.seq = seq;
}
return $result;
}
MsgNotify._() : super();
factory MsgNotify.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory MsgNotify.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'MsgNotify', createEmptyInstance: create)
..a<$core.int>(1, _omitFieldNames ? '' : 'seq', $pb.PbFieldType.OU3)
..hasRequiredFields = false
;
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
MsgNotify clone() => MsgNotify()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
MsgNotify copyWith(void Function(MsgNotify) updates) => super.copyWith((message) => updates(message as MsgNotify)) as MsgNotify;
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static MsgNotify create() => MsgNotify._();
MsgNotify createEmptyInstance() => create();
static $pb.PbList<MsgNotify> createRepeated() => $pb.PbList<MsgNotify>();
@$core.pragma('dart2js:noInline')
static MsgNotify getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<MsgNotify>(create);
static MsgNotify? _defaultInstance;
@$pb.TagNumber(1)
$core.int get seq => $_getIZ(0);
@$pb.TagNumber(1)
set seq($core.int v) { $_setUnsignedInt32(0, v); }
@$pb.TagNumber(1)
$core.bool hasSeq() => $_has(0);
@$pb.TagNumber(1)
void clearSeq() => clearField(1);
}
class MsgSync extends $pb.GeneratedMessage {
factory MsgSync({
$core.int? seq,
}) {
final $result = create();
if (seq != null) {
$result.seq = seq;
}
return $result;
}
MsgSync._() : super();
factory MsgSync.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory MsgSync.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'MsgSync', createEmptyInstance: create)
..a<$core.int>(1, _omitFieldNames ? '' : 'seq', $pb.PbFieldType.OU3)
..hasRequiredFields = false
;
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
MsgSync clone() => MsgSync()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
MsgSync copyWith(void Function(MsgSync) updates) => super.copyWith((message) => updates(message as MsgSync)) as MsgSync;
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static MsgSync create() => MsgSync._();
MsgSync createEmptyInstance() => create();
static $pb.PbList<MsgSync> createRepeated() => $pb.PbList<MsgSync>();
@$core.pragma('dart2js:noInline')
static MsgSync getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<MsgSync>(create);
static MsgSync? _defaultInstance;
@$pb.TagNumber(1)
$core.int get seq => $_getIZ(0);
@$pb.TagNumber(1)
set seq($core.int v) { $_setUnsignedInt32(0, v); }
@$pb.TagNumber(1)
$core.bool hasSeq() => $_has(0);
@$pb.TagNumber(1)
void clearSeq() => clearField(1);
}
class MsgSyncData extends $pb.GeneratedMessage {
factory MsgSyncData({
$core.Iterable<MsgData>? messages,
}) {
final $result = create();
if (messages != null) {
$result.messages.addAll(messages);
}
return $result;
}
MsgSyncData._() : super();
factory MsgSyncData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory MsgSyncData.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'MsgSyncData', createEmptyInstance: create)
..pc<MsgData>(1, _omitFieldNames ? '' : 'messages', $pb.PbFieldType.PM, subBuilder: MsgData.create)
..hasRequiredFields = false
;
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
MsgSyncData clone() => MsgSyncData()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
MsgSyncData copyWith(void Function(MsgSyncData) updates) => super.copyWith((message) => updates(message as MsgSyncData)) as MsgSyncData;
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static MsgSyncData create() => MsgSyncData._();
MsgSyncData createEmptyInstance() => create();
static $pb.PbList<MsgSyncData> createRepeated() => $pb.PbList<MsgSyncData>();
@$core.pragma('dart2js:noInline')
static MsgSyncData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<MsgSyncData>(create);
static MsgSyncData? _defaultInstance;
@$pb.TagNumber(1)
$core.List<MsgData> get messages => $_getList(0);
}
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');

36
lib/im/out/message.pbenum.dart

@ -0,0 +1,36 @@
//
// Generated code. Do not modify.
// source: message.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
class MsgType extends $pb.ProtobufEnum {
static const MsgType SINGLE_TEXT = MsgType._(0, _omitEnumNames ? '' : 'SINGLE_TEXT');
static const MsgType SINGLE_AUDIO = MsgType._(1, _omitEnumNames ? '' : 'SINGLE_AUDIO');
static const MsgType GROUP_TEXT = MsgType._(2, _omitEnumNames ? '' : 'GROUP_TEXT');
static const MsgType GROUP_AUDIO = MsgType._(3, _omitEnumNames ? '' : 'GROUP_AUDIO');
static const $core.List<MsgType> values = <MsgType> [
SINGLE_TEXT,
SINGLE_AUDIO,
GROUP_TEXT,
GROUP_AUDIO,
];
static final $core.Map<$core.int, MsgType> _byValue = $pb.ProtobufEnum.initByValue(values);
static MsgType? valueOf($core.int value) => _byValue[value];
const MsgType._($core.int v, $core.String n) : super(v, n);
}
const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names');

85
lib/im/out/message.pbjson.dart

@ -0,0 +1,85 @@
//
// Generated code. Do not modify.
// source: message.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
import 'dart:typed_data' as $typed_data;
@$core.Deprecated('Use msgTypeDescriptor instead')
const MsgType$json = {
'1': 'MsgType',
'2': [
{'1': 'SINGLE_TEXT', '2': 0},
{'1': 'SINGLE_AUDIO', '2': 1},
{'1': 'GROUP_TEXT', '2': 2},
{'1': 'GROUP_AUDIO', '2': 3},
],
};
/// Descriptor for `MsgType`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List msgTypeDescriptor = $convert.base64Decode(
'CgdNc2dUeXBlEg8KC1NJTkdMRV9URVhUEAASEAoMU0lOR0xFX0FVRElPEAESDgoKR1JPVVBfVE'
'VYVBACEg8KC0dST1VQX0FVRElPEAM=');
@$core.Deprecated('Use msgDataDescriptor instead')
const MsgData$json = {
'1': 'MsgData',
'2': [
{'1': 'to', '3': 1, '4': 1, '5': 9, '10': 'to'},
{'1': 'from', '3': 2, '4': 1, '5': 9, '10': 'from'},
{'1': 'ctime', '3': 3, '4': 1, '5': 13, '10': 'ctime'},
{'1': 'type', '3': 4, '4': 1, '5': 14, '6': '.MsgType', '10': 'type'},
{'1': 'data', '3': 5, '4': 1, '5': 12, '10': 'data'},
],
};
/// Descriptor for `MsgData`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List msgDataDescriptor = $convert.base64Decode(
'CgdNc2dEYXRhEg4KAnRvGAEgASgJUgJ0bxISCgRmcm9tGAIgASgJUgRmcm9tEhQKBWN0aW1lGA'
'MgASgNUgVjdGltZRIcCgR0eXBlGAQgASgOMgguTXNnVHlwZVIEdHlwZRISCgRkYXRhGAUgASgM'
'UgRkYXRh');
@$core.Deprecated('Use msgNotifyDescriptor instead')
const MsgNotify$json = {
'1': 'MsgNotify',
'2': [
{'1': 'seq', '3': 1, '4': 1, '5': 13, '10': 'seq'},
],
};
/// Descriptor for `MsgNotify`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List msgNotifyDescriptor = $convert.base64Decode(
'CglNc2dOb3RpZnkSEAoDc2VxGAEgASgNUgNzZXE=');
@$core.Deprecated('Use msgSyncDescriptor instead')
const MsgSync$json = {
'1': 'MsgSync',
'2': [
{'1': 'seq', '3': 1, '4': 1, '5': 13, '10': 'seq'},
],
};
/// Descriptor for `MsgSync`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List msgSyncDescriptor = $convert.base64Decode(
'CgdNc2dTeW5jEhAKA3NlcRgBIAEoDVIDc2Vx');
@$core.Deprecated('Use msgSyncDataDescriptor instead')
const MsgSyncData$json = {
'1': 'MsgSyncData',
'2': [
{'1': 'messages', '3': 1, '4': 3, '5': 11, '6': '.MsgData', '10': 'messages'},
],
};
/// Descriptor for `MsgSyncData`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List msgSyncDataDescriptor = $convert.base64Decode(
'CgtNc2dTeW5jRGF0YRIkCghtZXNzYWdlcxgBIAMoCzIILk1zZ0RhdGFSCG1lc3NhZ2Vz');

14
lib/im/out/message.pbserver.dart

@ -0,0 +1,14 @@
//
// Generated code. Do not modify.
// source: message.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
export 'message.pb.dart';

12
lib/main.dart

@ -14,6 +14,8 @@ import 'package:huixiang/community/community_details.dart';
import 'package:huixiang/community/release_dynamic.dart';
import 'package:huixiang/generated/l10n.dart';
import 'package:huixiang/home/founder_story_page.dart';
import 'package:huixiang/im/SocketClient.dart';
import 'package:huixiang/im/database/hx_database.dart';
import 'package:huixiang/integral/integral_detailed_page.dart';
import 'package:huixiang/integral/integral_page.dart';
import 'package:huixiang/integral_store/integral_store_details_page.dart';
@ -206,6 +208,8 @@ void main() async {
// initSdk();
bool isFirst = sharedPreferences.getBool("isFirst");
initDatabase();
runApp(MyApp(locale, isFirst));
// FlutterBugly.postCatchedException((){
// });
@ -214,8 +218,14 @@ void main() async {
// final XgFlutterPlugin xgFlutterPlugin = XgFlutterPlugin();
HxDatabase hxDatabase;
initDatabase() async {
hxDatabase = HxDatabase();
await hxDatabase.open();
}
final SocketClient socketClient = new SocketClient();
EventBus eventBus = EventBus(sync: true);
Route lastRoutePage;
@ -496,7 +506,7 @@ Map<String, WidgetBuilder> routers = <String, WidgetBuilder>{
'/router/contacts_share': (context, {arguments}) =>
ContactsShare(arguments:arguments),
'/router/chat_details_page': (context, {arguments}) =>
ChatDetailsPage(),
ChatDetailsPage(arguments: arguments),
'/router/chat_setting': (context, {arguments}) =>
ChatSetting(),
'/router/chat_friend_group': (context, {arguments}) =>

11
lib/main_page.dart

@ -9,6 +9,8 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:huixiang/community/community_page.dart';
import 'package:huixiang/generated/l10n.dart';
import 'package:huixiang/home/home_page.dart';
import 'package:huixiang/im/Proto.dart';
import 'package:huixiang/im/out/message.pb.dart';
import 'package:huixiang/main.dart';
import 'package:huixiang/mine/mine_page.dart';
import 'package:huixiang/retrofit/data/app_update.dart';
@ -66,6 +68,7 @@ class _MainPage extends State<MainPage> with WidgetsBindingObserver {
@override
void dispose() {
super.dispose();
socketClient.dispose();
WidgetsBinding.instance.removeObserver(this);
}
@ -90,9 +93,17 @@ class _MainPage extends State<MainPage> with WidgetsBindingObserver {
}
}
//socket服务
connectSocket() async {
socketClient.connect();
}
@override
void initState() {
super.initState();
connectSocket();
pageController = PageController(
initialPage:
widget.arguments != null && widget.arguments["index"] != null

3
lib/message/mine_message.dart

@ -36,7 +36,8 @@ class _MineMessagePage extends State<MineMessagePage> {
spreadRadius: 0,
)
],
borderRadius: BorderRadius.circular(8.w)),
borderRadius: BorderRadius.circular(8.w),
),
child: ListView.builder(
itemCount: 1,
shrinkWrap: true,

1
lib/mine/edit_signature.dart

@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:huixiang/generated/l10n.dart';
import 'package:huixiang/utils/font_weight.dart';
import 'package:huixiang/view_widget/my_appbar.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

112
pubspec.lock

@ -149,26 +149,26 @@ packages:
dependency: transitive
description:
name: crypto
sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.2"
version: "3.0.3"
csslib:
dependency: transitive
description:
name: csslib
sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745
sha256: "831883fb353c8bdc1d71979e5b342c7d88acfbc643113c14ae51e2442ea0f20f"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.17.2"
version: "0.17.3"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.5"
version: "1.0.6"
dio:
dependency: "direct main"
description:
@ -241,6 +241,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.1.4"
fixnum:
dependency: transitive
description:
name: fixnum
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0"
fl_chart:
dependency: "direct main"
description:
@ -351,10 +359,10 @@ packages:
dependency: "direct main"
description:
name: flutter_spinkit
sha256: b39c753e909d4796906c5696a14daf33639a76e017136c8d82bf3e620ce5bb8e
sha256: d2696eed13732831414595b98863260e33e8882fc069ee80ec35d4ac9ddb0472
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.2.0"
version: "5.2.1"
flutter_staggered_grid_view:
dependency: "direct main"
description:
@ -449,10 +457,10 @@ packages:
dependency: transitive
description:
name: html
sha256: "58e3491f7bf0b6a4ea5110c0c688877460d1a6366731155c4a4580e7ded773e8"
sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.15.3"
version: "0.15.4"
http_parser:
dependency: transitive
description:
@ -569,10 +577,10 @@ packages:
dependency: "direct main"
description:
name: mqtt_client
sha256: e8347f8996c33b80a6764a1881e94a8ef5392c2d6e724b9daad65eafa202b0c7
sha256: ba10ec490ded55dc4e77bbc992529d823fb15d0d5ec68c2895f960312060c541
url: "https://pub.flutter-io.cn"
source: hosted
version: "9.6.8"
version: "9.8.1"
nested:
dependency: transitive
description:
@ -665,10 +673,10 @@ packages:
dependency: transitive
description:
name: path_provider_linux
sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1"
sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.10"
version: "2.1.11"
path_provider_macos:
dependency: transitive
description:
@ -689,10 +697,10 @@ packages:
dependency: transitive
description:
name: path_provider_windows
sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6
sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.6"
version: "2.1.7"
permission_handler:
dependency: "direct main"
description:
@ -713,10 +721,10 @@ packages:
dependency: transitive
description:
name: petitparser
sha256: "2ebb289dc4764ec397f5cd3ca9881c6d17196130a7d646ed022a0dd9c2e25a71"
sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4"
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.0.0"
version: "5.1.0"
photo_view:
dependency: "direct main"
description:
@ -729,18 +737,18 @@ packages:
dependency: "direct main"
description:
name: pin_input_text_field
sha256: "569861876d5c67994adc58ddd15e93bd0057c4f26d7e5599ccde880d05813463"
sha256: f45683032283d30b670ec343781660655e3e1953438b281a0bc6e2d358486236
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.4.1"
version: "4.5.2"
platform:
dependency: transitive
description:
name: platform
sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.0"
version: "3.1.3"
plugin_platform_interface:
dependency: transitive
description:
@ -757,22 +765,22 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.7.3"
process:
dependency: transitive
protobuf:
dependency: "direct main"
description:
name: process
sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
name: protobuf
sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d"
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.2.4"
version: "3.1.0"
provider:
dependency: transitive
description:
name: provider
sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.0.5"
version: "6.1.2"
pull_to_refresh:
dependency: "direct main"
description:
@ -801,10 +809,10 @@ packages:
dependency: transitive
description:
name: quiver
sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47
sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.2.1"
version: "3.2.2"
retrofit:
dependency: "direct main"
description:
@ -897,10 +905,10 @@ packages:
dependency: "direct main"
description:
name: sharesdk_plugin
sha256: "76bccf3ecfaf41a9182502d8ce7e3de838646ce656095ca3153baf20ba6ae72d"
sha256: a1a18d01f362c119df1931082e3694591a24b3b00eef2576522e00ef8da3b25e
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.6"
version: "1.3.10"
shimmer:
dependency: "direct main"
description:
@ -930,6 +938,22 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.9.1"
sqflite:
dependency: "direct main"
description:
name: sqflite
sha256: b4d6710e1200e96845747e37338ea8a819a12b51689a3bcf31eff0003b37a0b9
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.8+4"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
sha256: "8f7603f3f8f126740bc55c4ca2d1027aab4b74a1267a3e31ce51fe40e3b65b8f"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.4.5+1"
stack_trace:
dependency: transitive
description:
@ -978,6 +1002,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "19.4.56"
synchronized:
dependency: transitive
description:
name: synchronized
sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.0"
table_calendar:
dependency: "direct main"
description:
@ -1047,10 +1079,10 @@ packages:
dependency: "direct main"
description:
name: umeng_common_sdk
sha256: fce28065224b0839ffc16b5003d2295dae8aabee290bf639f978536b32ed601d
sha256: "60d7ac8093d42e236dbecb5fc8558b16644808a70d24514ad926be7ddf56d5e9"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.6"
version: "1.2.7"
url_launcher:
dependency: "direct main"
description:
@ -1127,10 +1159,10 @@ packages:
dependency: transitive
description:
name: video_player_avfoundation
sha256: "5df5411ff9d316f1dcbfee284e9838aa686e314f2a722b15c02cb7ce40ef9446"
sha256: "90468226c8687adf7b567d9bb42c25588783c4d30509af1fbd663b2dd049f700"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.3.9"
version: "2.4.2"
video_player_platform_interface:
dependency: transitive
description:
@ -1223,10 +1255,10 @@ packages:
dependency: transitive
description:
name: xdg_directories
sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1
sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.0"
version: "1.0.3"
xml:
dependency: transitive
description:
@ -1237,4 +1269,4 @@ packages:
version: "5.4.1"
sdks:
dart: ">=2.19.0 <3.0.0"
flutter: ">=3.0.0"
flutter: ">=3.7.0"

5
pubspec.yaml

@ -123,9 +123,12 @@ dependencies:
flutter_datetime_picker: ^1.5.1
widgetpicker: ^0.1.1
# floor: ^1.4.2
sqflite: ^2.2.2
syncfusion_flutter_datepicker: ^19.4.38
protobuf: ^3.1.0
dev_dependencies:
flutter_test:
sdk: flutter

Loading…
Cancel
Save