From c53b119e60e102e5e093943b41a62c78da55f1df Mon Sep 17 00:00:00 2001 From: hrxiang Date: Tue, 14 Sep 2021 17:33:19 +0800 Subject: [PATCH] upgrade sdk --- .idea/Open-IM-SDK-Flutter.iml | 3 + README.zh-cn.md | 821 ++++++++++++++++++ android/build.gradle | 2 +- .../manager/MessageManager.java | 6 + .../flutter_openim_sdk/util/CommonUtil.java | 5 + lib/src/enum/message_type.dart | 3 +- lib/src/manager/im_friendship_manager.dart | 11 + lib/src/manager/im_group_manager.dart | 25 + lib/src/manager/im_message_manager.dart | 16 +- lib/src/models/conversation_info.dart | 5 + lib/src/models/message.dart | 53 +- lib/src/models/user_info.dart | 7 +- 12 files changed, 945 insertions(+), 12 deletions(-) create mode 100644 README.zh-cn.md 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; }