diff --git a/.idea/Open-IM-SDK-Flutter.iml b/.idea/Open-IM-SDK-Flutter.iml
index 55d90fc..5ed57ce 100644
--- a/.idea/Open-IM-SDK-Flutter.iml
+++ b/.idea/Open-IM-SDK-Flutter.iml
@@ -9,6 +9,9 @@
+
+
+
diff --git a/README.zh-cn.md b/README.zh-cn.md
new file mode 100644
index 0000000..26bf688
--- /dev/null
+++ b/README.zh-cn.md
@@ -0,0 +1,821 @@
+
+
+## 1,初始化
+
+```
+OpenIM.iMManager.initSDK(
+ //参考IMPlatform类
+ platform: Platform.isAndroid ? IMPlatform.android : IMPlatform.ios,
+ ipApi: '',
+ ipWs: '',
+ dbPath: '',
+ listener: OnInitSDKListener(
+ connecting: () {
+ // 正在连接到服务器
+ },
+ connectFailed: (code, error) {
+ // 连接服务器失败
+ },
+ connectSuccess: () {
+ // 已经成功连接到服务器
+ },
+ kickedOffline: () {
+ // 当前用户被踢下线
+ },
+ userSigExpired: () {
+ // 登录票据已经过期
+ },
+ selfInfoUpdated: (info) {
+ // 当前用户的资料发生了更新
+ },
+ ),
+ );
+```
+
+初始化接口包含五个必填参数 (platform,ipApi,ipWs,dbPath,listener)
+
+#### platform
+
+类IMPlatform的值
+
+```
+class IMPlatform {
+ static const ios = 1;
+ static const android = 2;
+ static const windows = 3;
+ static const xos = 4;
+ static const web = 5;
+ static const mini_web = 6;
+ static const linux = 7;
+}
+```
+
+#### ipApi
+
+SDK的API接口地址。如:http:xxx:10000
+
+#### ipWs
+
+SDK的web socket地址。如: ws:xxx:17778
+
+#### dbPath
+
+数据缓存路径。如:var apath =(await getApplicationDocumentsDirectory()).path
+
+ 注:在创建图片,语音,视频,文件等需要路径参数的消息体时,如果选择的是非全路径方法如:createSoundMessage(全路径方法为:createSoundMessageFromFullPath),需要将文件自行拷贝到apath目录下,如果此时文件路径为 apath+"/sound/a.mp3",则参数path的值为:/sound/a.mp3。如果选择的全路径方法,路径为你文件的实际路径不需要再拷贝。
+
+#### listener
+
+初始化监听回调
+
+| 事件回调 | 事件描述 | 推荐操作 |
+| ----------------- | ------------------------ | ------------------------------------------------------------ |
+| onConnecting | 正在连接到服务器 | 适合在 UI 上展示“正在连接”状态。 |
+| onConnectSuccess | 连接服务器失败 | - |
+| onConnectFailed | 已经成功连接到服务器 | 可以提示用户当前网络连接不可用 |
+| onKickedOffline | 当前用户被踢下线 | 此时可以 UI 提示用户“您已经在其他端登录了当前账号,是否重新登录?” |
+| onUserSigExpired | 登录票据已经过期 | 请使用新签发的 UserSig 进行登录。 |
+| onSelfInfoUpdated | 当前用户的资料发生了更新 | 可以在 UI 上更新自己的头像和昵称。 |
+
+### 2,登录
+
+```
+OpenIM.iMManager.login(uid: uid, token: token);
+```
+
+参数uid跟token为必传参数,它们的值通过接口地址 http://xxx/auth/user_token获取
+
+#### 获取当前用户id
+
+```
+OpenIM.iMManager.getLoginUid()
+```
+
+#### 获取当前用户信息
+
+```
+OpenIM.iMManager.getLoginUserInfo();
+```
+
+#### 获取登录状态
+
+```
+OpenIM.iMManager.getLoginStatus();
+```
+
+### 3,会话
+
+#### 拉取当前所有的会话记录,返回Future>
+
+```
+OpenIM.iMManager.conversationManager.getAllConversationList()
+```
+
+如果你想获取单个回话使用方法getSingleConversation,该方法有两个必传参数sourceID和sessionType。sourceID:如果是单聊其值为单聊对象的userId;如果是群聊其值为群的groupId。sessionType:如果是单聊sessionType=1;群聊sessionType=2。
+
+如果你想获取多个回话使用方法getMultipleConversation,参数多个回话id
+
+#### 删除会话
+
+执行此操作会触发会话记录发生改变回调。
+
+```
+OpenIM.iMManager.conversationManager.deleteConversation(
+ conversationID: conversationID,
+);
+```
+
+参数当前被删除的会话的id
+
+#### 置顶会话
+
+执行此操作会触发会话记录发生改变回调。
+
+```
+OpenIM.iMManager.conversationManager.pinConversation(
+ conversationID: conversationID,
+ isPinned: true,
+);
+```
+
+isPinned:true置顶,false取消置顶。
+
+注:ConversationInfo对象里的isPinned字段,isPinned==1代表置顶
+
+#### 设置草稿
+
+执行此操作会触发会话记录发生改变回调。
+
+```
+OpenIM.iMManager.conversationManager.setConversationDraft(
+ conversationID: conversationID,
+ draftText: draftText,
+);
+```
+
+draftText(草稿):未完成发送的消息内容。
+
+#### 设置会话监听
+
+会话记录发生改变时回调。
+
+```
+OpenIM.iMManager.conversationManager.setConversationListener(OnConversationListener(
+ conversationChanged: (list){
+ // 会话记录改变
+ },
+ newConversation: (list){
+ // 新增会话
+ },
+ totalUnreadMsgCountChanged: (count){
+ // 未读消息总数改变
+ },
+ syncServerFailed: () {},
+ syncServerFinish: () {},
+ syncServerStart: () {},
+));
+```
+
+| 事件回调 | 事件描述 | 推荐操作 |
+| -------------------------- | -------------------- | -------------- |
+| conversationChanged | 会话记录发生改变 | 刷新会话列表 |
+| newConversation | 有新的会话被添加 | 刷新会话列表 |
+| totalUnreadMsgCountChanged | 未读消息总数发生改变 | 刷新消息未读数 |
+
+### 4,好友关系
+
+#### 查询好友列表,返回Future>
+
+```
+OpenIM.iMManager.friendshipManager.getFriendList();
+```
+
+如果需要做联系人A-Z列表效果,推荐使用方法getFriendListMap, 该方法返回值为Future> ,然后再将list转换为你自己的List Object,如:
+
+```
+OpenIM.iMManager.friendshipManager.getFriendListMap()
+ .then((list) => list.map((e) => ContactsInfo.fromJson(e)).toList());
+```
+
+#### 添加好友
+
+```
+OpenIM.iMManager.friendshipManager.addFriend(uid: uid, reason: reason);
+```
+
+uid必传参数,值为被添加的用户uid。reason:添加说明,非必传参数。返回Future,执行then方法为添加成功,执行cathError方法为添加失败。
+
+#### 删除好友
+
+```
+OpenIM.iMManager.friendshipManager.deleteFromFriendList(uid: uid);
+```
+
+返回Future,执行then方法为删除成功,执行cathError方法为删除失败。
+
+#### 检查好友关系
+
+返回Future>
+
+```
+OpenIM.iMManager.friendshipManager.checkFriend([id1,id2, ...]);
+```
+
+根据类UserInfo的flag字段判断。flag == 1:是好友关系,其他非好友关系。
+
+#### 获取好友信息
+
+返回Future>
+
+```
+OpenIM.iMManager.getFriendsInfo([id1,id2, ...]);
+```
+
+#### 为好友添加备注
+
+```
+OpenIM.iMManager.friendshipManager.setFriendInfo(info: UserInfo(uid: uid, comment: ’这是备注‘))
+```
+
+参数info:UserInfo类,uid:好友的id,comment:备注。
+
+注:只能为好友添加备注,其他好友信息无权限修改。
+
+#### 获取好友申请列表
+
+返回Future>
+
+```
+OpenIM.iMManager.friendshipManager.getFriendApplicationList();
+```
+
+类UserInfo的flag字段:flag == 0:等待处理;flag == 1:已添加;flag == -1:已拒绝。
+
+注:新朋友的红点数通过计算列表里flag == 0的item的数量。
+
+#### 同意被加为好友
+
+```
+OpenIM.iMManager.friendshipManager.acceptFriendApplication(uid: uid)
+```
+
+uid:为好友申请列表返回的数据里UserInfo类的uid字段。返回Future,执行then方法为操作成功,执行cathError方法为操作失败。
+
+#### 拒绝被加为好友
+
+```
+OpenIM.iMManager.friendshipManager.refuseFriendApplication(uid: uid)
+```
+
+返回Future,执行then方法为操作成功,执行cathError方法为操作失败。
+
+#### 黑名单列表
+
+返回Future>
+
+```
+OpenIM.iMManager.friendshipManager.getBlackList();
+```
+
+注:如果好友被拉进黑名单,调用getFriendList 或 getFriendListMap方法得到好友包含了黑名单的人,需要通过UserInfo类的isInBlackList字段筛选,如果isInBlackList == 1说明被拉入黑名单。
+
+#### 拉入黑名单
+
+```
+OpenIM.iMManager.friendshipManager.addToBlackList(uid: uid)
+```
+
+#### 从黑名单移除
+
+```
+OpenIM.iMManager.friendshipManager.deleteFromBlackList(uid: uid);
+```
+
+#### 设置关系改变监听
+
+```
+OpenIM.iMManager.friendshipManager.setFriendshipListener(OnFriendshipListener(
+ blackListAdd: (u){
+ // 好友被加入黑名时单回调
+ },
+ blackListDeleted: (u){
+ // 好友从黑名单移除时回调
+ },
+ friendApplicationListAccept: (u){
+ // 发起的好友请求被接受时回调
+ },
+ friendApplicationListAdded: (u){
+ // 我接受被人的发起的好友请求时回调
+ },
+ friendApplicationListDeleted: (u){
+ // 删除好友请求时回调
+ },
+ friendApplicationListReject: (u){
+ // 请求被拒绝回调
+ },
+ friendInfoChanged: (u){
+ // 好友资料发生变化时回调
+ },
+ friendListAdded: (u){
+ // 已添加好友回调
+ },
+ friendListDeleted: (u){
+ // 好友被删除时回调
+ },
+));
+```
+
+| 事件回调 | 事件描述 | 推荐操作 |
+| ---------------------------- | -------------------------- | ---------------------------------- |
+| blackListAdd | 好友被加入黑名 | 刷新好友列表或黑名单列表 |
+| blackListDeleted | 好友从黑名单移除 | 刷新好友列表或黑名单列表 |
+| friendApplicationListAccept | 发起的好友请求被接受 | 刷新好友请求列表 |
+| friendApplicationListAdded | 我接受被人的发起的好友请求 | 刷新好友请求列表 |
+| friendApplicationListDeleted | 删除好友请求 | 刷新好友请求列表 |
+| friendApplicationListReject | 请求被拒绝 | 刷新好友请求列表 |
+| friendInfoChanged | 好友资料发生变化 | 刷新好友列表,好友信息或黑名单列表 |
+| friendListAdded | 已成为好友 | 刷新好友列表 |
+| friendListDeleted | 好友被删除 | 刷新好友列表 |
+
+### 5,群关系
+
+#### 获取已加入的群列表
+
+返回Future>
+
+```
+OpenIM.iMManager.groupManager.getJoinedGroupList();
+```
+
+如果类GroupInfo的ownerId字段的值跟当前用户的uid一致,则当前用户就是群的发起者。否则是参与者。
+
+#### 创建群
+
+```
+OpenIM.iMManager.groupManager.createGroup(
+ groupInfo: info,
+ list: roles,
+)
+```
+
+参数info(GroupInfo):群资料,非必传;参数roles(List)在发起群聊时选择的群成员列表,必传字段。
+
+GroupInfo类字段说明:groupName群名;notification群公告;introduction群介绍;faceUrl群icon。
+
+GroupMemberRole类字段说明:setRole:0:普通成员 2:管理员;uid:成员的uid。
+
+#### 获取群信息
+
+根据群id获取群的信息,返回Future>
+
+```
+OpenIM.iMManager.groupManager.getGroupsInfo(gidList: [gid1,gid2,...]);
+```
+
+#### 设置群信息
+
+```
+OpenIM.iMManager.groupManager.setGroupInfo(groupInfo: gInfo)
+```
+
+只能设置群的名称(groupName),公告(notification),介绍(introduction)和icon(faceUrl)。groupID为系统生成的ID不能更改。ownerId也不能修改,修改群的拥有者需要调用群权限交接方法transferGroupOwner。
+
+#### 获取群成员列表
+
+返回Future ,GroupMembersList类的nextSeq字段:下一页的开始index。data字段:群成员。
+
+```
+OpenIM.iMManager.groupManager.getGroupMemberList(groupId: gid)
+```
+
+groupId:群id,必传。
+
+filter:过滤成员,0不过滤,1群的创建者,2管理员, 非必传,默认值0。
+
+next:分页,从哪一条开始获取,默认值0。参照nextSeq的值。
+
+#### 邀请进群
+
+```
+OpenIM.iMManager.groupManager.inviteUserToGroup(
+ groupId: gid,
+ uidList: uidList,
+ reason: reason,
+);
+```
+
+gid:群的id,uidList:被邀请的好友uid,reason:邀请说明。
+
+#### 踢出群
+
+```
+OpenIM.iMManager.groupManager.kickGroupMember(
+ groupId: gid,
+ uidList: uidList,
+ reason: reason,
+);
+```
+
+#### 申请加群
+
+```
+OpenIM.iMManager.groupManager.joinGroup(gid: gid, reason: null)
+```
+
+#### 变更群拥有者(发起者)
+
+```
+OpenIM.iMManager.groupManager.transferGroupOwner(gid: gid, uid: uid)
+```
+
+uid:新的拥有者uid。此方法只有群的发起者(拥有者)才有权限访问,管理员和普通成员无权限访问。如果是发起者群资料展示可显示群权限转移按钮。
+
+#### 退群
+
+```
+OpenIM.iMManager.groupManager.quitGroup(gid: gid)
+```
+
+#### 群监听
+
+```
+OpenIM.iMManager.groupManager.setGroupListener(OnGroupListener(
+ applicationProcessed: (groupId, opUser, agreeOrReject, opReason){
+ // 群申请被处理时回调
+ },
+ groupCreated: (groupId){
+ // 群创建完成时回调
+ },
+ groupInfoChanged: (groupId, info){
+ // 群资料发生变化时回调
+ },
+ memberEnter: ( groupId, list){
+ // 有人进群时回调
+ },
+ memberInvited: ( groupId, opUser, list){
+ // 接受邀请时回调
+ },
+ memberKicked: ( groupId, opUser, list){
+ // 成员被踢出时回调
+ },
+ memberLeave: ( groupId, info){
+ // 群成员退群时回调
+ },
+ receiveJoinApplication: ( groupId, info, opReason){
+ // 收到入群申请
+ },
+))
+```
+
+| 事件回调 | 事件描述 | 推荐操作 |
+| ---------------------- | -------------- | -------------- |
+| applicationProcessed | 群申请被处理 | |
+| groupCreated | 群创建完成 | |
+| groupInfoChanged | 群资料发生变化 | 刷新群资料 |
+| memberEnter | 进群 | 刷新群成员列表 |
+| memberInvited | 接受邀请 | 刷新群成员列表 |
+| memberKicked | 成员被踢出 | 刷新群成员列表 |
+| memberLeave | 群成员退群 | 刷新群成员列表 |
+| receiveJoinApplication | 收到入群申请 | |
+
+### 6,消息
+
+#### 创建文本消息
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager.createTextMessage(
+ text: '这里是消息内容',
+)
+```
+
+#### 创建@消息
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager.createTextAtMessage(
+ text: '消息内容',
+ atUidList: [uid1,uid2,...],
+);
+```
+
+atUidList:被@到的用户uid。
+
+#### 创建图片消息
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager.createImageMessage(
+ imagePath: '图片的相对路径',
+)
+```
+
+注:initSDK时传入了数据缓存路径,如路径:A,这时需要你将图片复制到A路径下后,如 A/pic/a.png路径,imagePath的值:“/pic/a.png”。
+
+#### 创建图片消息(全路径)
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager.createImageMessageFromFullPath(
+ imagePath: path,
+)
+```
+
+path: 文件在设备上的的实际路径。此方法不需要拷贝,推荐使用。
+
+#### 创建语音消息
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager.createSoundMessage(
+ soundPath: '相对路径',
+ duration: '语音时长',
+)
+```
+
+注:initSDK时传入了数据缓存路径,如路径:A,这时需要你将语音文件复制到A路径下后,如 A/sound/a.m4a路径,soundPath的值:“/sound/a.m4a”。
+
+#### 创建语音消息(全路径)
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager.createSoundMessageFromFullPath(
+ soundPath: path,
+ duration: duration,
+)
+```
+
+soundPath: 文件在设备上的的实际路径。此方法不需要拷贝,推荐使用。
+
+#### 创建视频消息
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager
+ .createVideoMessage(
+ videoPath: path,
+ videoType: type,
+ duration: duration,
+ snapshotPath: tPath)
+```
+
+videoPath:相对路径。videoType:文件的mineType。duration: 视频时长。snapshotPath:视频的缩略图。
+
+注:initSDK时传入了数据缓存路径,如路径:A,这时需要你将视频文件复制到A路径下后,如 A/video/a.mp4路径,videoPath的值:“/video/a.mp4”
+
+#### 创建视频消息(全路径)
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager.createVideoMessageFromFullPath(
+ videoPath: videoPath,
+ videoType: mimeType,
+ duration: duration,
+ snapshotPath: thumbnailPath,
+)
+```
+
+videoPath: 文件在设备上的的实际路径。此方法不需要拷贝,推荐使用。
+
+#### 创建文件消息
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager.createFileMessage(
+ filePath: filePath,
+ fileName: fileName,
+);
+```
+
+filePath: 文件的相对路径,fileName:文件名
+
+注:initSDK时传入了数据缓存路径,如路径:A,这时需要你将视频文件复制到A路径下后,如 A/file/a.txt路径,filePath的值:“/file/a.txt”
+
+#### 创建文件消息(全路径)
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager.createFileMessageFromFullPath(
+ filePath: filePath,
+ fileName: fileName,
+)
+```
+
+filePath: 文件在设备上的的实际路径。此方法不需要拷贝,推荐使用。
+
+#### 创建位置消息
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager.createLocationMessage(
+ latitude: ’纬度‘,
+ longitude: ’经度‘,
+ description: ’描述信息,可以根据自己的需求传任何数据‘,
+)
+```
+
+description:在位置消息展示时,有位置名,位置描述,定位图片信息。推荐 description:{"title":"天府新谷","detail":"四川省高新区石羊街道府城大道西段399号","url":"https://apis.map.qq.com/ws/staticmap/v2/?center=%s&zoom=18&size=600*300&maptype=roadmap&markers=size:large|color:0xFFCCFF|label:k|%s&key=TMNBZ-3CGC6-C6SSL-EJA3B-E2P5Q-V7F6Q"}
+
+#### 创建引用消息
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager.createQuoteMessage(
+ text: '消息内容',
+ quoteMsg: '被引用的消息对象Message',
+)
+```
+
+#### 创建名片消息
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager.createCardMessage(
+ data: '用户信息Map',
+)
+```
+
+data接收一个Map值:如{"uid": uid, 'name': name, 'icon': icon},按需求定义。
+
+#### 创建合并消息
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager.createMergerMessage(
+ messageList: '被选中的消息',
+ title: '标题',
+ summaryList: '摘要',
+)
+```
+
+#### 创建转发消息
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager.createForwardMessage(
+ message: '被转发的Message',
+)
+```
+
+#### 创建自定义消息
+
+返回Future
+
+```
+OpenIM.iMManager.messageManager.createCustomMessage(
+ data: '自定义数据',
+ extension: '自定义数据',
+ description: '自定义数据',
+ )
+```
+
+#### 发送消息
+
+```
+OpenIM.iMManager.messageManager
+ .sendMessage(
+ message: message,
+ userID: userId,
+ groupID: groupId,
+ )
+ .then((value) => _sendSucceeded(message))
+ .catchError((e) => _senFailed(message, e))
+ .whenComplete(() => _completed())
+```
+
+message:创建的消息体。userID:用户id。groupID:组id。如果一对一聊天 userID不能为空。如果群聊天groupID不能为空。如果消息发送成功执行then方法,发送失败执行catchError方法。
+
+#### 提示用户正在输入
+
+```
+OpenIM.iMManager.messageManager.typingStatusUpdate(
+ userID: uid,
+ typing: '',
+)
+```
+
+单聊使用此功能。userID单聊对象id。typing:true正在输入,false停止输入。
+
+注:在收到的新消息回调里如果消息类型为typing消息且typing == 'yes'提示正在输入。typing=='no'取消提示
+
+#### 撤回消息
+
+```
+OpenIM.iMManager.messageManager.revokeMessage(message: message)
+```
+
+message:被撤回的消息体。
+
+注:调用此方法会触发消息撤回回调,可以在回调里移除界面上的消息显示。也会触发新增消息回调,新增的消息类型为撤回消息类型,可以在界面显示一条xx撤回了一条消息
+
+#### 标记消息为已读
+
+```
+OpenIM.iMManager.messageManager.markC2CMessageAsRead(
+ userID: userID,
+ messageIDList: [msgId1,msgId2,..],
+)
+```
+
+单聊使用此功能。userID单聊对象id。messageIDList:被标记为已读消息的消息id。
+
+注:调用此方法会触发c2c消息已读回调,可以在回调里修改界面上的消息已读状态
+
+#### 获取聊天记录
+
+```
+OpenIM.iMManager.messageManager
+ .getHistoryMessageList(
+ userID: '单聊对象id',
+ groupID: '群聊群id',
+ count: '获取的条数',
+ startMsg:'从哪一个消息开始'
+ )
+```
+
+如果是单聊窗口userID不能为空,如果是群聊窗口groupID不能为空。startMsg:如第一次拉取20条记录startMsg=null&&count=20得到List list;下一次拉取消息记录参数:startMsg=list.first && count =20;以此内推,startMsg始终为list的第一条。
+
+#### 设置消息监听
+
+```
+OpenIM.iMManager.messageManager.addAdvancedMsgListener(OnAdvancedMsgListener(
+ recvMessageRevoked: (msgId){
+ // 消息被撤回回调
+ var revokedMsg = Message(clientMsgID: msgId);
+ messageList.remove(revokedMsg);
+ },
+ recvC2CReadReceipt: (List list){
+ // 消息已读回执
+ messageList.forEach((e) {
+ // 获取当前聊天窗口的已读回执
+ var info = list.firstWhere((element) => element.uid == uid);
+ // 标记消息列表里对应的消息为已读状态
+ if (info.msgIDList?.contains(e.clientMsgID) == true) {
+ e.isRead = true;
+ }
+ });
+ },
+ recvNewMessage: (msg){
+ // 如果是当前窗口的消息
+ if (isCurrentChat(message)) {
+ // 正在输入消息
+ if (message.contentType == MessageType.typing) {
+ //
+ } else {
+ // 新增消息
+ if (!messageList.contains(message)) {
+ messageList.add(message);
+ }
+ }
+ }
+ },
+))
+```
+
+| 事件回调 | 事件描述 | 推荐操作 |
+| ------------------ | -------------- | ---------------- |
+| recvMessageRevoked | 消息成功撤回 | 从界面移除消息 |
+| recvC2CReadReceipt | 消息被阅读回执 | 将消息标记为已读 |
+| recvNewMessage | 收到新消息 | 界面添加新消息 |
+
+#### 消息发送进度监听
+
+主要用途:图片,视频,文件等上传进度监听。
+
+```
+OpenIM.iMManager.messageManager.setMsgSendProgressListener(OnMsgSendProgressListener(
+ progressCallback: (String msgId, int progress){
+ // 根据消息id,判断图片等上传进度
+ },
+))
+```
+
+### 7,退出
+
+#### 反初始化
+
+```
+OpenIM.iMManager.unInitSDK();
+```
+
+#### 登出
+
+```
+OpenIM.iMManager.logout();
+```
+
diff --git a/android/build.gradle b/android/build.gradle
index ccf590d..3d0322d 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -52,5 +52,5 @@ android {
}
dependencies {
// implementation 'io.openim:client:0.0.13@aar'
- implementation 'io.openim:client-sdk:0.0.9@aar'
+ implementation 'io.openim:client-sdk:0.0.11@aar'
}
\ No newline at end of file
diff --git a/android/src/main/java/io/openim/flutter_openim_sdk/manager/MessageManager.java b/android/src/main/java/io/openim/flutter_openim_sdk/manager/MessageManager.java
index a022996..04864b6 100644
--- a/android/src/main/java/io/openim/flutter_openim_sdk/manager/MessageManager.java
+++ b/android/src/main/java/io/openim/flutter_openim_sdk/manager/MessageManager.java
@@ -235,6 +235,12 @@ public class MessageManager {
));
}
+ public void createCardMessage(MethodCall methodCall, MethodChannel.Result result) {
+ CommonUtil.runMainThreadReturn(result, Open_im_sdk.createCardMessage(
+ CommonUtil.getCardMessage(methodCall)
+ ));
+ }
+
public void getTotalUnreadMsgCount(MethodCall methodCall, MethodChannel.Result result) {
Open_im_sdk.getTotalUnreadMsgCount(new BaseListener(result));
}
diff --git a/android/src/main/java/io/openim/flutter_openim_sdk/util/CommonUtil.java b/android/src/main/java/io/openim/flutter_openim_sdk/util/CommonUtil.java
index 106246f..b8aedff 100644
--- a/android/src/main/java/io/openim/flutter_openim_sdk/util/CommonUtil.java
+++ b/android/src/main/java/io/openim/flutter_openim_sdk/util/CommonUtil.java
@@ -292,6 +292,10 @@ public class CommonUtil {
return getSDKJsonParam(methodCall, KEY_QUOTE_MESSAGE_BODY);
}
+ public static String getCardMessage(MethodCall methodCall) {
+ return getSDKJsonParam(methodCall, KEY_CARD_MESSAGE);
+ }
+
//login
final static String KEY_UID = "uid";
final static String KEY_TOKEN = "token";
@@ -318,6 +322,7 @@ public class CommonUtil {
final static String KEY_CUSTOM_MESSAGE_EXT = "extension";
final static String KEY_QUOTE_MESSAGE_TEXT = "quoteText";
final static String KEY_QUOTE_MESSAGE_BODY = "quoteMessage";
+ final static String KEY_CARD_MESSAGE = "cardMessage";
//send message
final static String KEY_SEND_MESSAGE_CONTENT = "message";
final static String KEY_SEND_MESSAGE_CONTENT_CLIENT_ID = "clientMsgID";
diff --git a/lib/src/enum/message_type.dart b/lib/src/enum/message_type.dart
index c861e6a..01fc18d 100644
--- a/lib/src/enum/message_type.dart
+++ b/lib/src/enum/message_type.dart
@@ -7,7 +7,8 @@ class MessageType {
static const file = 105;
static const at_text = 106;
static const merger = 107;
- static const forward = 108;
+ // static const forward = 108;
+ static const card = 108;
static const location = 109;
static const custom = 110;
static const revoke = 111;
diff --git a/lib/src/manager/im_friendship_manager.dart b/lib/src/manager/im_friendship_manager.dart
index d2fca67..54deaf3 100644
--- a/lib/src/manager/im_friendship_manager.dart
+++ b/lib/src/manager/im_friendship_manager.dart
@@ -47,6 +47,12 @@ class FriendshipManager {
.then((value) => _toList(value));
}
+ Future> getFriendListMap() {
+ return _channel
+ .invokeMethod('getFriendList', _buildParam({}))
+ .then((value) => _toListMap(value));
+ }
+
/// modify friend information, only [comment] can be modified
///
Future setFriendInfo({required UserInfo info}) {
@@ -131,6 +137,11 @@ class FriendshipManager {
return (list as List).map((e) => UserInfo.fromJson(e)).toList();
}
+ static List _toListMap(String? value) {
+ var list = _formatJson(value);
+ return list;
+ }
+
static UserInfo _toObj(String value) => UserInfo.fromJson(_formatJson(value));
static dynamic _formatJson(value) {
diff --git a/lib/src/manager/im_group_manager.dart b/lib/src/manager/im_group_manager.dart
index bb5cfcc..48ff34b 100644
--- a/lib/src/manager/im_group_manager.dart
+++ b/lib/src/manager/im_group_manager.dart
@@ -90,6 +90,24 @@ class GroupManager {
.then((value) => GroupMembersList.fromJson(_formatJson(value)));
}
+// filter 0: all user, 1: group owner, 2: administrator
+ /// begin index, pull and fill 0 for the first time
+ Future getGroupMemberListMap({
+ required String groupId,
+ int filter = 0,
+ int next = 0,
+ }) {
+ return _channel
+ .invokeMethod(
+ 'getGroupMemberList',
+ _buildParam({
+ 'gid': groupId,
+ 'filter': filter,
+ 'next': next,
+ }))
+ .then((value) => _formatJson(value));
+ }
+
/// find all groups you have joined
Future> getJoinedGroupList() {
return _channel.invokeMethod('getJoinedGroupList', _buildParam({})).then(
@@ -98,6 +116,13 @@ class GroupManager {
.toList());
}
+ /// find all groups you have joined
+ Future> getJoinedGroupListMap() {
+ return _channel
+ .invokeMethod('getJoinedGroupList', _buildParam({}))
+ .then((value) => _formatJson(value));
+ }
+
/// check
Future isJoinedGroup({required String gid}) {
return getJoinedGroupList()
diff --git a/lib/src/manager/im_message_manager.dart b/lib/src/manager/im_message_manager.dart
index 53ef661..3305f7c 100644
--- a/lib/src/manager/im_message_manager.dart
+++ b/lib/src/manager/im_message_manager.dart
@@ -302,12 +302,12 @@ class MessageManager {
}
///
- Future createForwardMessage({required List messageList}) {
+ Future createForwardMessage({required Message message}) {
return _channel
.invokeMethod(
'createForwardMessage',
_buildParam({
- 'message': messageList.map((e) => e.toJson()).toList(),
+ 'message': message.toJson(),
}))
.then((value) => _toObj(value));
}
@@ -361,6 +361,18 @@ class MessageManager {
.then((value) => _toObj(value));
}
+ Future createCardMessage({
+ required Map data,
+ }) {
+ return _channel
+ .invokeMethod(
+ 'createCardMessage',
+ _buildParam({
+ 'cardMessage': data,
+ }))
+ .then((value) => _toObj(value));
+ }
+
///
Future getTotalUnreadMsgCount() {
return _channel.invokeMethod('getTotalUnreadMsgCount', _buildParam({}));
diff --git a/lib/src/models/conversation_info.dart b/lib/src/models/conversation_info.dart
index d164c96..6da93ad 100644
--- a/lib/src/models/conversation_info.dart
+++ b/lib/src/models/conversation_info.dart
@@ -4,6 +4,7 @@ import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
class ConversationInfo {
String conversationID;
+ /// [ConversationType]
int? conversationType;
String? userID;
String? groupID;
@@ -15,6 +16,8 @@ class ConversationInfo {
int? latestMsgSendTime;
String? draftText;
int? draftTimestamp;
+
+ /// pinned value is 1
dynamic isPinned;
ConversationInfo(
@@ -78,4 +81,6 @@ class ConversationInfo {
bool get isSingleChat => conversationType == ConversationType.single_chat;
bool get isGroupChat => conversationType == ConversationType.group_chat;
+
+ bool get isTop => isPinned == 1;
}
diff --git a/lib/src/models/message.dart b/lib/src/models/message.dart
index 8a7cdee..be1e1ae 100644
--- a/lib/src/models/message.dart
+++ b/lib/src/models/message.dart
@@ -8,6 +8,8 @@ class Message {
String? sendID;
String? recvID;
int? msgFrom;
+
+ /// [MessageType]
int? contentType;
int? platformID;
List? forceList;
@@ -17,9 +19,13 @@ class Message {
String? content;
int? seq;
bool? isRead;
+
+ /// [MessageStatus]
int? status;
String? remark;
dynamic ext;
+
+ /// [ConversationType]
int? sessionType;
PictureElem? pictureElem;
SoundElem? soundElem;
@@ -29,6 +35,7 @@ class Message {
LocationElem? locationElem;
CustomElem? customElem;
QuoteElem? quoteElem;
+ MergeElem? mergeElem;
Message({
this.clientMsgID,
@@ -59,6 +66,7 @@ class Message {
this.locationElem,
this.customElem,
this.quoteElem,
+ this.mergeElem,
});
Message.fromJson(Map json)
@@ -107,6 +115,9 @@ class Message {
quoteElem = json['quoteElem'] != null
? QuoteElem.fromJson(json['quoteElem'])
: null;
+ mergeElem = json['mergeElem'] != null
+ ? MergeElem.fromJson(json['mergeElem'])
+ : null;
}
Map toJson() {
@@ -139,6 +150,7 @@ class Message {
data['locationElem'] = this.locationElem?.toJson();
data['customElem'] = this.customElem?.toJson();
data['quoteElem'] = this.quoteElem?.toJson();
+ data['mergeElem'] = this.mergeElem?.toJson();
return data;
}
@@ -450,6 +462,34 @@ class QuoteElem {
}
}
+class MergeElem {
+ String? title;
+ List? abstractList;
+ List? multiMessage;
+
+ MergeElem({this.title, this.abstractList, this.multiMessage});
+
+ MergeElem.fromJson(Map json) {
+ title = json['title'];
+ if (json['abstractList'] is List) {
+ abstractList = json['abstractList'].cast();
+ }
+ if (json['multiMessage'] is List) {
+ multiMessage = (json['abstractList'] as List)
+ .map((e) => Message.fromJson(e))
+ .toList();
+ }
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['title'] = this.title;
+ data['abstractList'] = this.abstractList;
+ data['multiMessage'] = this.multiMessage?.map((e) => e.toJson()).toList();
+ return data;
+ }
+}
+
class HaveReadInfo {
String? uid;
List? msgIDList;
@@ -458,12 +498,13 @@ class HaveReadInfo {
int? contentType;
int? sessionType;
- HaveReadInfo({this.uid,
- this.msgIDList,
- this.readTime,
- this.msgFrom,
- this.contentType,
- this.sessionType});
+ HaveReadInfo(
+ {this.uid,
+ this.msgIDList,
+ this.readTime,
+ this.msgFrom,
+ this.contentType,
+ this.sessionType});
HaveReadInfo.fromJson(Map json) {
uid = json['uid'];
diff --git a/lib/src/models/user_info.dart b/lib/src/models/user_info.dart
index 7f65657..7f642da 100644
--- a/lib/src/models/user_info.dart
+++ b/lib/src/models/user_info.dart
@@ -77,9 +77,12 @@ class UserInfo {
/// blacklist
bool get isBlocked => isInBlackList == 1;
- /// friend application
+ /// friend application waiting handle
+ bool get isWaitingHandle => flag == 0;
+
+ /// friend application agreed
bool get isAgreed => flag == 1;
- /// friend application
+ /// friend application rejected
bool get isRejected => flag == -1;
}