初步替换IM接口
This commit is contained in:
@@ -84,7 +84,7 @@ import com.aiosman.ravenow.ui.composables.MenuItem
|
||||
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
|
||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
import com.aiosman.ravenow.utils.NetworkUtils
|
||||
import com.tencent.imsdk.v2.V2TIMMessage
|
||||
import io.openim.android.sdk.enums.MessageType
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.UUID
|
||||
|
||||
@@ -379,18 +379,18 @@ fun ChatAiSelfItem(item: ChatItem) {
|
||||
modifier = Modifier
|
||||
.widthIn(
|
||||
min = 20.dp,
|
||||
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
||||
max = (if (item.messageType == MessageType.TEXT) 250.dp else 150.dp)
|
||||
)
|
||||
.clip(RoundedCornerShape(20.dp))
|
||||
.background(Color(0xFF6246FF))
|
||||
.padding(
|
||||
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
||||
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
||||
vertical = (if (item.messageType == MessageType.TEXT) 8.dp else 0.dp),
|
||||
horizontal = (if (item.messageType == MessageType.TEXT) 16.dp else 0.dp)
|
||||
)
|
||||
|
||||
) {
|
||||
when (item.messageType) {
|
||||
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
||||
MessageType.TEXT -> {
|
||||
Text(
|
||||
text = item.message,
|
||||
style = TextStyle(
|
||||
@@ -401,7 +401,7 @@ fun ChatAiSelfItem(item: ChatItem) {
|
||||
)
|
||||
}
|
||||
|
||||
V2TIMMessage.V2TIM_ELEM_TYPE_IMAGE -> {
|
||||
MessageType.PICTURE -> {
|
||||
CustomAsyncImage(
|
||||
imageUrl = item.imageList[1].url,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
@@ -467,18 +467,18 @@ fun ChatAiOtherItem(item: ChatItem) {
|
||||
modifier = Modifier
|
||||
.widthIn(
|
||||
min = 20.dp,
|
||||
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
||||
max = (if (item.messageType == MessageType.TEXT) 250.dp else 150.dp)
|
||||
)
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.background(AppColors.bubbleBackground)
|
||||
.padding(
|
||||
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
||||
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
||||
vertical = (if (item.messageType == MessageType.TEXT) 8.dp else 0.dp),
|
||||
horizontal = (if (item.messageType == MessageType.TEXT) 16.dp else 0.dp)
|
||||
)
|
||||
.padding(bottom = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 3.dp else 0.dp))
|
||||
.padding(bottom = (if (item.messageType == MessageType.TEXT) 3.dp else 0.dp))
|
||||
) {
|
||||
when (item.messageType) {
|
||||
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
||||
MessageType.TEXT -> {
|
||||
Text(
|
||||
text = item.message,
|
||||
style = TextStyle(
|
||||
@@ -489,7 +489,7 @@ fun ChatAiOtherItem(item: ChatItem) {
|
||||
)
|
||||
}
|
||||
|
||||
V2TIMMessage.V2TIM_ELEM_TYPE_IMAGE -> {
|
||||
MessageType.PICTURE -> {
|
||||
CustomAsyncImage(
|
||||
imageUrl = item.imageList[1].url,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
|
||||
@@ -23,13 +23,13 @@ import com.aiosman.ravenow.entity.AccountProfileEntity
|
||||
import com.aiosman.ravenow.entity.ChatItem
|
||||
import com.aiosman.ravenow.entity.ChatNotification
|
||||
import com.aiosman.ravenow.ui.navigateToChatAi
|
||||
import com.tencent.imsdk.v2.V2TIMAdvancedMsgListener
|
||||
import com.tencent.imsdk.v2.V2TIMCallback
|
||||
import com.tencent.imsdk.v2.V2TIMConversationOperationResult
|
||||
import com.tencent.imsdk.v2.V2TIMManager
|
||||
import com.tencent.imsdk.v2.V2TIMMessage
|
||||
import com.tencent.imsdk.v2.V2TIMSendCallback
|
||||
import com.tencent.imsdk.v2.V2TIMValueCallback
|
||||
// OpenIM SDK 导入
|
||||
import io.openim.android.sdk.OpenIMClient
|
||||
import io.openim.android.sdk.enums.ViewType
|
||||
import io.openim.android.sdk.listener.OnAdvanceMsgListener
|
||||
import io.openim.android.sdk.listener.OnBase
|
||||
import io.openim.android.sdk.listener.OnMsgSendCallback
|
||||
import io.openim.android.sdk.models.*
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
@@ -44,10 +44,10 @@ class ChatAiViewModel(
|
||||
var myProfile by mutableStateOf<AccountProfileEntity?>(null)
|
||||
val userService: UserService = UserServiceImpl()
|
||||
val accountService: AccountService = AccountServiceImpl()
|
||||
var textMessageListener: V2TIMAdvancedMsgListener? = null
|
||||
var textMessageListener: OnAdvanceMsgListener? = null
|
||||
var hasMore by mutableStateOf(true)
|
||||
var isLoading by mutableStateOf(false)
|
||||
var lastMessage: V2TIMMessage? = null
|
||||
var lastMessage: Message? = null
|
||||
val showTimestampMap = mutableMapOf<String, Boolean>() // Add this map
|
||||
var chatNotification by mutableStateOf<ChatNotification?>(null)
|
||||
var goToNew by mutableStateOf(false)
|
||||
@@ -68,9 +68,14 @@ class ChatAiViewModel(
|
||||
|
||||
|
||||
fun RegistListener(context: Context) {
|
||||
textMessageListener = object : V2TIMAdvancedMsgListener() {
|
||||
override fun onRecvNewMessage(msg: V2TIMMessage?) {
|
||||
super.onRecvNewMessage(msg)
|
||||
// 检查 OpenIM 是否已登录
|
||||
if (!com.aiosman.ravenow.AppState.enableChat) {
|
||||
android.util.Log.w("ChatAiViewModel", "OpenIM 未登录,跳过注册消息监听器")
|
||||
return
|
||||
}
|
||||
|
||||
textMessageListener = object : OnAdvanceMsgListener {
|
||||
override fun onRecvNewMessage(msg: Message?) {
|
||||
msg?.let { message ->
|
||||
// 只处理当前聊天对象的消息
|
||||
val currentChatUserId = userProfile?.trtcUserId
|
||||
@@ -78,38 +83,41 @@ class ChatAiViewModel(
|
||||
|
||||
if (currentChatUserId != null && currentUserId != null) {
|
||||
// 检查消息是否来自当前聊天对象,且不是自己发送的消息
|
||||
if ((message.userID == currentChatUserId || message.userID == currentUserId) &&
|
||||
message.sender != currentUserId) {
|
||||
if ((message.sendID == currentChatUserId || message.sendID == currentUserId) &&
|
||||
message.sendID != currentUserId) {
|
||||
val chatItem = ChatItem.convertToChatItem(message, context, avatar = userProfile?.avatar)
|
||||
chatItem?.let {
|
||||
chatData = listOf(it) + chatData
|
||||
goToNew = true
|
||||
android.util.Log.i("ChatAiViewModel", "收到来自 ${message.sender} 的消息,更新AI聊天列表")
|
||||
android.util.Log.i("ChatAiViewModel", "收到来自 ${message.sendID} 的消息,更新AI聊天列表")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
V2TIMManager.getMessageManager().addAdvancedMsgListener(textMessageListener);
|
||||
OpenIMClient.getInstance().messageManager.setAdvancedMsgListener(textMessageListener)
|
||||
}
|
||||
|
||||
fun UnRegistListener() {
|
||||
V2TIMManager.getMessageManager().removeAdvancedMsgListener(textMessageListener);
|
||||
// OpenIM SDK 不需要显式移除监听器,只需要设置为 null
|
||||
textMessageListener = null
|
||||
}
|
||||
|
||||
fun clearUnRead() {
|
||||
val conversationID = "c2c_${userProfile?.trtcUserId}"
|
||||
V2TIMManager.getConversationManager()
|
||||
.cleanConversationUnreadMessageCount(conversationID, 0, 0, object : V2TIMCallback {
|
||||
override fun onSuccess() {
|
||||
Log.i("imsdk", "success")
|
||||
val conversationID = "single_${userProfile?.trtcUserId}"
|
||||
OpenIMClient.getInstance().messageManager.markConversationMessageAsRead(
|
||||
conversationID,
|
||||
object : OnBase<String> {
|
||||
override fun onSuccess(data: String?) {
|
||||
Log.i("openim", "clear unread success")
|
||||
}
|
||||
|
||||
override fun onError(code: Int, desc: String) {
|
||||
Log.i("imsdk", "failure, code:$code, desc:$desc")
|
||||
override fun onError(code: Int, error: String?) {
|
||||
Log.i("openim", "clear unread failure, code:$code, error:$error")
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -119,117 +127,124 @@ class ChatAiViewModel(
|
||||
}
|
||||
isLoading = true
|
||||
viewModelScope.launch {
|
||||
V2TIMManager.getMessageManager().getC2CHistoryMessageList(
|
||||
userProfile?.trtcUserId!!,
|
||||
20,
|
||||
lastMessage,
|
||||
object : V2TIMValueCallback<List<V2TIMMessage>> {
|
||||
override fun onSuccess(p0: List<V2TIMMessage>?) {
|
||||
chatData = chatData + (p0 ?: emptyList()).map {
|
||||
val conversationID = "single_${userProfile?.trtcUserId!!}"
|
||||
// val options = OpenIMClient.getInstance().messageManager.getAdvancedHistoryMessageList() .apply {
|
||||
// conversationID = conversationID
|
||||
// count = 20
|
||||
// lastMinSeq = lastMessage?.seq ?: 0
|
||||
// }
|
||||
OpenIMClient.getInstance().messageManager.getAdvancedHistoryMessageList(
|
||||
object : OnBase<AdvancedMessage> {
|
||||
override fun onSuccess(data: AdvancedMessage?) {
|
||||
val messages = data?.messageList ?: emptyList()
|
||||
chatData = chatData + messages.map {
|
||||
var avatar = userProfile?.avatar
|
||||
if (it.isSelf) {
|
||||
if (it.sendID == com.aiosman.ravenow.AppState.profile?.trtcUserId) {
|
||||
avatar = myProfile?.avatar
|
||||
}
|
||||
ChatItem.convertToChatItem(it, context,avatar)
|
||||
ChatItem.convertToChatItem(it, context, avatar)
|
||||
}.filterNotNull()
|
||||
if ((p0?.size ?: 0) < 20) {
|
||||
|
||||
if (messages.size < 20) {
|
||||
hasMore = false
|
||||
}
|
||||
lastMessage = p0?.lastOrNull()
|
||||
lastMessage = messages.lastOrNull()
|
||||
isLoading = false
|
||||
Log.d("ChatViewModel", "fetch history message success")
|
||||
Log.d("ChatAiViewModel", "fetch history message success")
|
||||
}
|
||||
|
||||
override fun onError(p0: Int, p1: String?) {
|
||||
Log.e("ChatViewModel", "fetch history message error: $p1")
|
||||
override fun onError(code: Int, error: String?) {
|
||||
Log.e("ChatAiViewModel", "fetch history message error: $error")
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
},
|
||||
conversationID,
|
||||
lastMessage,
|
||||
20,
|
||||
ViewType.History
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun sendMessage(message: String, context: Context) {
|
||||
V2TIMManager.getInstance().sendC2CTextMessage(
|
||||
message,
|
||||
userProfile?.trtcUserId!!,
|
||||
object : V2TIMSendCallback<V2TIMMessage> {
|
||||
override fun onProgress(p0: Int) {
|
||||
|
||||
// 检查 OpenIM 是否已登录
|
||||
if (!com.aiosman.ravenow.AppState.enableChat) {
|
||||
android.util.Log.w("ChatAiViewModel", "OpenIM 未登录,无法发送消息")
|
||||
return
|
||||
}
|
||||
|
||||
val textMessage = OpenIMClient.getInstance().messageManager.createTextMessage(message)
|
||||
|
||||
OpenIMClient.getInstance().messageManager.sendMessage(
|
||||
object : OnMsgSendCallback {
|
||||
override fun onProgress(progress: Long) {
|
||||
// 发送进度
|
||||
}
|
||||
|
||||
override fun onError(p0: Int, p1: String?) {
|
||||
Log.e("ChatViewModel", "send message error: $p1")
|
||||
override fun onError(code: Int, error: String?) {
|
||||
Log.e("ChatAiViewModel", "send message error: $error")
|
||||
}
|
||||
|
||||
override fun onSuccess(p0: V2TIMMessage?) {
|
||||
Log.d("ChatViewModel", "send message success")
|
||||
sendChatAiMessage(myProfile?.trtcUserId!!,userProfile?.trtcUserId!!, message)
|
||||
createGroup2ChatAi(userProfile?.trtcUserId!!,"ai_group")
|
||||
val chatItem = ChatItem.convertToChatItem(p0!!, context, avatar = myProfile?.avatar)
|
||||
chatItem?.let {
|
||||
chatData = listOf(it) + chatData
|
||||
goToNew = true
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
fun createGroup2ChatAi(
|
||||
trtcUserId: String,
|
||||
groupName: String,
|
||||
) {
|
||||
val conversationIDList = listOf("c2c_${trtcUserId}")
|
||||
|
||||
V2TIMManager.getConversationManager().createConversationGroup(
|
||||
groupName,
|
||||
conversationIDList,
|
||||
object : V2TIMValueCallback<List<V2TIMConversationOperationResult>> {
|
||||
override fun onSuccess(v2TIMConversationOperationResults: List<V2TIMConversationOperationResult>) {
|
||||
// 创建会话分组成功
|
||||
}
|
||||
|
||||
override fun onError(code: Int, desc: String) {
|
||||
// 创建会话分组失败
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
fun sendImageMessage(imageUri: Uri, context: Context) {
|
||||
val tempFile = createTempFile(context, imageUri)
|
||||
val imagePath = tempFile?.path
|
||||
if (imagePath != null) {
|
||||
val v2TIMMessage = V2TIMManager.getMessageManager().createImageMessage(imagePath)
|
||||
V2TIMManager.getMessageManager().sendMessage(
|
||||
v2TIMMessage,
|
||||
userProfile?.trtcUserId!!,
|
||||
null,
|
||||
V2TIMMessage.V2TIM_PRIORITY_NORMAL,
|
||||
false,
|
||||
null,
|
||||
object : V2TIMSendCallback<V2TIMMessage> {
|
||||
override fun onProgress(p0: Int) {
|
||||
Log.d("ChatViewModel", "send image message progress: $p0")
|
||||
}
|
||||
|
||||
override fun onError(p0: Int, p1: String?) {
|
||||
Log.e("ChatViewModel", "send image message error: $p1")
|
||||
}
|
||||
|
||||
override fun onSuccess(p0: V2TIMMessage?) {
|
||||
Log.d("ChatViewModel", "send image message success")
|
||||
val chatItem = ChatItem.convertToChatItem(p0!!, context, avatar = myProfile?.avatar)
|
||||
override fun onSuccess(data: Message?) {
|
||||
Log.d("ChatAiViewModel", "send message success")
|
||||
sendChatAiMessage(myProfile?.trtcUserId!!, userProfile?.trtcUserId!!, message)
|
||||
createGroup2ChatAi(userProfile?.trtcUserId!!, "ai_group")
|
||||
data?.let { sentMessage ->
|
||||
val chatItem = ChatItem.convertToChatItem(sentMessage, context, avatar = myProfile?.avatar)
|
||||
chatItem?.let {
|
||||
chatData = listOf(it) + chatData
|
||||
goToNew = true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
textMessage,
|
||||
userProfile?.trtcUserId!!, // recvID
|
||||
null, // groupID
|
||||
null // offlinePushInfo
|
||||
)
|
||||
}
|
||||
fun createGroup2ChatAi(
|
||||
trtcUserId: String,
|
||||
groupName: String,
|
||||
) {
|
||||
// OpenIM 不支持会话分组功能,这里可以留空或者使用其他方式实现
|
||||
Log.d("ChatAiViewModel", "OpenIM 不支持会话分组功能")
|
||||
}
|
||||
|
||||
fun sendImageMessage(imageUri: Uri, context: Context) {
|
||||
val tempFile = createTempFile(context, imageUri)
|
||||
val imagePath = tempFile?.path
|
||||
if (imagePath != null) {
|
||||
val imageMessage = OpenIMClient.getInstance().messageManager.createImageMessageFromFullPath(imagePath)
|
||||
|
||||
OpenIMClient.getInstance().messageManager.sendMessage(
|
||||
object : OnMsgSendCallback {
|
||||
override fun onProgress(progress: Long) {
|
||||
Log.d("ChatAiViewModel", "send image message progress: $progress")
|
||||
}
|
||||
|
||||
override fun onError(code: Int, error: String?) {
|
||||
Log.e("ChatAiViewModel", "send image message error: $error")
|
||||
}
|
||||
|
||||
override fun onSuccess(data: Message?) {
|
||||
Log.d("ChatAiViewModel", "send image message success")
|
||||
data?.let { sentMessage ->
|
||||
val chatItem = ChatItem.convertToChatItem(sentMessage, context, avatar = myProfile?.avatar)
|
||||
chatItem?.let {
|
||||
chatData = listOf(it) + chatData
|
||||
goToNew = true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
imageMessage,
|
||||
userProfile?.trtcUserId!!, // recvID
|
||||
null, // groupID
|
||||
null // offlinePushInfo
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun createTempFile(context: Context, uri: Uri): File? {
|
||||
@@ -264,30 +279,35 @@ class ChatAiViewModel(
|
||||
}
|
||||
|
||||
fun fetchHistoryMessage(context: Context) {
|
||||
V2TIMManager.getMessageManager().getC2CHistoryMessageList(
|
||||
userProfile?.trtcUserId!!,
|
||||
20,
|
||||
null,
|
||||
object : V2TIMValueCallback<List<V2TIMMessage>> {
|
||||
override fun onSuccess(p0: List<V2TIMMessage>?) {
|
||||
chatData = (p0 ?: emptyList()).mapNotNull {
|
||||
val conversationID = "single_${userProfile?.trtcUserId!!}"
|
||||
|
||||
|
||||
OpenIMClient.getInstance().messageManager.getAdvancedHistoryMessageList(
|
||||
object : OnBase<AdvancedMessage> {
|
||||
override fun onSuccess(data: AdvancedMessage?) {
|
||||
val messages = data?.messageList ?: emptyList()
|
||||
chatData = messages.mapNotNull {
|
||||
var avatar = userProfile?.avatar
|
||||
if (it.isSelf) {
|
||||
if (it.sendID == com.aiosman.ravenow.AppState.profile?.trtcUserId) {
|
||||
avatar = myProfile?.avatar
|
||||
}
|
||||
ChatItem.convertToChatItem(it, context,avatar)
|
||||
ChatItem.convertToChatItem(it, context, avatar)
|
||||
}
|
||||
if ((p0?.size ?: 0) < 20) {
|
||||
if (messages.size < 20) {
|
||||
hasMore = false
|
||||
}
|
||||
lastMessage = p0?.lastOrNull()
|
||||
Log.d("ChatViewModel", "fetch history message success")
|
||||
lastMessage = messages.lastOrNull()
|
||||
Log.d("ChatAiViewModel", "fetch history message success")
|
||||
}
|
||||
|
||||
override fun onError(p0: Int, p1: String?) {
|
||||
Log.e("ChatViewModel", "fetch history message error: $p1")
|
||||
override fun onError(code: Int, error: String?) {
|
||||
Log.e("ChatAiViewModel", "fetch history message error: $error")
|
||||
}
|
||||
}
|
||||
},
|
||||
conversationID,
|
||||
lastMessage,
|
||||
20,
|
||||
ViewType.History
|
||||
)
|
||||
}
|
||||
fun sendChatAiMessage(
|
||||
|
||||
@@ -84,7 +84,7 @@ import com.aiosman.ravenow.ui.composables.MenuItem
|
||||
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
|
||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
import com.aiosman.ravenow.utils.NetworkUtils
|
||||
import com.tencent.imsdk.v2.V2TIMMessage
|
||||
import io.openim.android.sdk.enums.MessageType
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.UUID
|
||||
|
||||
@@ -379,18 +379,18 @@ fun ChatSelfItem(item: ChatItem) {
|
||||
modifier = Modifier
|
||||
.widthIn(
|
||||
min = 20.dp,
|
||||
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
||||
max = (if (item.messageType == MessageType.TEXT) 250.dp else 150.dp)
|
||||
)
|
||||
.clip(RoundedCornerShape(20.dp))
|
||||
.background(Color(0xFF6246FF))
|
||||
.padding(
|
||||
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
||||
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
||||
vertical = (if (item.messageType == MessageType.TEXT) 8.dp else 0.dp),
|
||||
horizontal = (if (item.messageType == MessageType.TEXT) 16.dp else 0.dp)
|
||||
)
|
||||
|
||||
) {
|
||||
when (item.messageType) {
|
||||
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
||||
MessageType.TEXT -> {
|
||||
Text(
|
||||
text = item.message,
|
||||
style = TextStyle(
|
||||
@@ -401,7 +401,7 @@ fun ChatSelfItem(item: ChatItem) {
|
||||
)
|
||||
}
|
||||
|
||||
V2TIMMessage.V2TIM_ELEM_TYPE_IMAGE -> {
|
||||
MessageType.PICTURE -> {
|
||||
CustomAsyncImage(
|
||||
imageUrl = item.imageList[1].url,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
@@ -467,18 +467,18 @@ fun ChatOtherItem(item: ChatItem) {
|
||||
modifier = Modifier
|
||||
.widthIn(
|
||||
min = 20.dp,
|
||||
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
||||
max = (if (item.messageType == MessageType.TEXT) 250.dp else 150.dp)
|
||||
)
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.background(AppColors.background)
|
||||
.padding(
|
||||
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
||||
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
||||
vertical = (if (item.messageType == MessageType.TEXT) 8.dp else 0.dp),
|
||||
horizontal = (if (item.messageType == MessageType.TEXT) 16.dp else 0.dp)
|
||||
)
|
||||
.padding(bottom = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 3.dp else 0.dp))
|
||||
.padding(bottom = (if (item.messageType == MessageType.TEXT) 3.dp else 0.dp))
|
||||
) {
|
||||
when (item.messageType) {
|
||||
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
||||
MessageType.TEXT -> {
|
||||
Text(
|
||||
text = item.message,
|
||||
style = TextStyle(
|
||||
@@ -489,7 +489,7 @@ fun ChatOtherItem(item: ChatItem) {
|
||||
)
|
||||
}
|
||||
|
||||
V2TIMMessage.V2TIM_ELEM_TYPE_IMAGE -> {
|
||||
MessageType.PICTURE -> {
|
||||
CustomAsyncImage(
|
||||
imageUrl = item.imageList[1].url,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
|
||||
@@ -18,12 +18,14 @@ import com.aiosman.ravenow.data.UserServiceImpl
|
||||
import com.aiosman.ravenow.entity.AccountProfileEntity
|
||||
import com.aiosman.ravenow.entity.ChatItem
|
||||
import com.aiosman.ravenow.entity.ChatNotification
|
||||
import com.tencent.imsdk.v2.V2TIMAdvancedMsgListener
|
||||
import com.tencent.imsdk.v2.V2TIMCallback
|
||||
import com.tencent.imsdk.v2.V2TIMManager
|
||||
import com.tencent.imsdk.v2.V2TIMMessage
|
||||
import com.tencent.imsdk.v2.V2TIMSendCallback
|
||||
import com.tencent.imsdk.v2.V2TIMValueCallback
|
||||
// OpenIM SDK 导入
|
||||
import io.openim.android.sdk.OpenIMClient
|
||||
import io.openim.android.sdk.enums.MessageType
|
||||
import io.openim.android.sdk.enums.ViewType
|
||||
import io.openim.android.sdk.listener.OnAdvanceMsgListener
|
||||
import io.openim.android.sdk.listener.OnBase
|
||||
import io.openim.android.sdk.listener.OnMsgSendCallback
|
||||
import io.openim.android.sdk.models.*
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
@@ -38,10 +40,10 @@ class ChatViewModel(
|
||||
var myProfile by mutableStateOf<AccountProfileEntity?>(null)
|
||||
val userService: UserService = UserServiceImpl()
|
||||
val accountService: AccountService = AccountServiceImpl()
|
||||
var textMessageListener: V2TIMAdvancedMsgListener? = null
|
||||
var textMessageListener: OnAdvanceMsgListener? = null
|
||||
var hasMore by mutableStateOf(true)
|
||||
var isLoading by mutableStateOf(false)
|
||||
var lastMessage: V2TIMMessage? = null
|
||||
var lastMessage: Message? = null
|
||||
val showTimestampMap = mutableMapOf<String, Boolean>() // Add this map
|
||||
var chatNotification by mutableStateOf<ChatNotification?>(null)
|
||||
var goToNew by mutableStateOf(false)
|
||||
@@ -62,9 +64,14 @@ class ChatViewModel(
|
||||
|
||||
|
||||
fun RegistListener(context: Context) {
|
||||
textMessageListener = object : V2TIMAdvancedMsgListener() {
|
||||
override fun onRecvNewMessage(msg: V2TIMMessage?) {
|
||||
super.onRecvNewMessage(msg)
|
||||
// 检查 OpenIM 是否已登录
|
||||
if (!com.aiosman.ravenow.AppState.enableChat) {
|
||||
android.util.Log.w("ChatViewModel", "OpenIM 未登录,跳过注册消息监听器")
|
||||
return
|
||||
}
|
||||
|
||||
textMessageListener = object : OnAdvanceMsgListener {
|
||||
override fun onRecvNewMessage(msg: Message?) {
|
||||
msg?.let { message ->
|
||||
// 只处理当前聊天对象的消息
|
||||
val currentChatUserId = userProfile?.trtcUserId
|
||||
@@ -72,38 +79,41 @@ class ChatViewModel(
|
||||
|
||||
if (currentChatUserId != null && currentUserId != null) {
|
||||
// 检查消息是否来自当前聊天对象,且不是自己发送的消息
|
||||
if ((message.userID == currentChatUserId || message.userID == currentUserId) &&
|
||||
message.sender != currentUserId) {
|
||||
if ((message.sendID == currentChatUserId || message.sendID == currentUserId) &&
|
||||
message.sendID != currentUserId) {
|
||||
val chatItem = ChatItem.convertToChatItem(message, context, avatar = userProfile?.avatar)
|
||||
chatItem?.let {
|
||||
chatData = listOf(it) + chatData
|
||||
goToNew = true
|
||||
android.util.Log.i("ChatViewModel", "收到来自 ${message.sender} 的消息,更新聊天列表")
|
||||
android.util.Log.i("ChatViewModel", "收到来自 ${message.sendID} 的消息,更新聊天列表")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
V2TIMManager.getMessageManager().addAdvancedMsgListener(textMessageListener);
|
||||
OpenIMClient.getInstance().messageManager.setAdvancedMsgListener(textMessageListener)
|
||||
}
|
||||
|
||||
fun UnRegistListener() {
|
||||
V2TIMManager.getMessageManager().removeAdvancedMsgListener(textMessageListener);
|
||||
// OpenIM SDK 不需要显式移除监听器,只需要设置为 null
|
||||
textMessageListener = null
|
||||
}
|
||||
|
||||
fun clearUnRead() {
|
||||
val conversationID = "c2c_${userProfile?.trtcUserId}"
|
||||
V2TIMManager.getConversationManager()
|
||||
.cleanConversationUnreadMessageCount(conversationID, 0, 0, object : V2TIMCallback {
|
||||
override fun onSuccess() {
|
||||
Log.i("imsdk", "success")
|
||||
val conversationID = "single_${userProfile?.trtcUserId}"
|
||||
OpenIMClient.getInstance().messageManager.markConversationMessageAsRead(
|
||||
conversationID,
|
||||
object : OnBase<String> {
|
||||
override fun onSuccess(data: String?) {
|
||||
Log.i("openim", "clear unread success")
|
||||
}
|
||||
|
||||
override fun onError(code: Int, desc: String) {
|
||||
Log.i("imsdk", "failure, code:$code, desc:$desc")
|
||||
override fun onError(code: Int, error: String?) {
|
||||
Log.i("openim", "clear unread failure, code:$code, error:$error")
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -113,58 +123,75 @@ class ChatViewModel(
|
||||
}
|
||||
isLoading = true
|
||||
viewModelScope.launch {
|
||||
V2TIMManager.getMessageManager().getC2CHistoryMessageList(
|
||||
userProfile?.trtcUserId!!,
|
||||
20,
|
||||
lastMessage,
|
||||
object : V2TIMValueCallback<List<V2TIMMessage>> {
|
||||
override fun onSuccess(p0: List<V2TIMMessage>?) {
|
||||
chatData = chatData + (p0 ?: emptyList()).map {
|
||||
val conversationID = "single_${userProfile?.trtcUserId!!}"
|
||||
|
||||
OpenIMClient.getInstance().messageManager.getAdvancedHistoryMessageList(
|
||||
object : OnBase<AdvancedMessage> {
|
||||
override fun onSuccess(data: AdvancedMessage?) {
|
||||
val messages = data?.messageList ?: emptyList()
|
||||
chatData = chatData + messages.map {
|
||||
var avatar = userProfile?.avatar
|
||||
if (it.isSelf) {
|
||||
if (it.sendID == com.aiosman.ravenow.AppState.profile?.trtcUserId) {
|
||||
avatar = myProfile?.avatar
|
||||
}
|
||||
ChatItem.convertToChatItem(it, context,avatar)
|
||||
ChatItem.convertToChatItem(it, context, avatar)
|
||||
}.filterNotNull()
|
||||
if ((p0?.size ?: 0) < 20) {
|
||||
|
||||
if (messages.size < 20) {
|
||||
hasMore = false
|
||||
}
|
||||
lastMessage = p0?.lastOrNull()
|
||||
lastMessage = messages.lastOrNull()
|
||||
isLoading = false
|
||||
Log.d("ChatViewModel", "fetch history message success")
|
||||
}
|
||||
|
||||
override fun onError(p0: Int, p1: String?) {
|
||||
Log.e("ChatViewModel", "fetch history message error: $p1")
|
||||
override fun onError(code: Int, error: String?) {
|
||||
Log.e("ChatViewModel", "fetch history message error: $error")
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
},
|
||||
conversationID,
|
||||
lastMessage,
|
||||
20,
|
||||
ViewType.History
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun sendMessage(message: String, context: Context) {
|
||||
V2TIMManager.getInstance().sendC2CTextMessage(
|
||||
message,
|
||||
userProfile?.trtcUserId!!,
|
||||
object : V2TIMSendCallback<V2TIMMessage> {
|
||||
override fun onProgress(p0: Int) {
|
||||
|
||||
// 检查 OpenIM 是否已登录
|
||||
if (!com.aiosman.ravenow.AppState.enableChat) {
|
||||
android.util.Log.w("ChatViewModel", "OpenIM 未登录,无法发送消息")
|
||||
return
|
||||
}
|
||||
|
||||
val textMessage = OpenIMClient.getInstance().messageManager.createTextMessage(message)
|
||||
|
||||
OpenIMClient.getInstance().messageManager.sendMessage(
|
||||
object : OnMsgSendCallback {
|
||||
override fun onProgress(progress: Long) {
|
||||
// 发送进度
|
||||
}
|
||||
|
||||
override fun onError(p0: Int, p1: String?) {
|
||||
Log.e("ChatViewModel", "send message error: $p1")
|
||||
override fun onError(code: Int, error: String?) {
|
||||
Log.e("ChatViewModel", "send message error: $error")
|
||||
}
|
||||
|
||||
override fun onSuccess(p0: V2TIMMessage?) {
|
||||
override fun onSuccess(data: Message?) {
|
||||
Log.d("ChatViewModel", "send message success")
|
||||
val chatItem = ChatItem.convertToChatItem(p0!!, context, avatar = myProfile?.avatar)
|
||||
chatItem?.let {
|
||||
chatData = listOf(it) + chatData
|
||||
goToNew = true
|
||||
data?.let { sentMessage ->
|
||||
val chatItem = ChatItem.convertToChatItem(sentMessage, context, avatar = myProfile?.avatar)
|
||||
chatItem?.let {
|
||||
chatData = listOf(it) + chatData
|
||||
goToNew = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
textMessage,
|
||||
userProfile?.trtcUserId!!, // recvID
|
||||
null, // groupID
|
||||
null // offlinePushInfo
|
||||
)
|
||||
}
|
||||
|
||||
@@ -172,35 +199,35 @@ class ChatViewModel(
|
||||
val tempFile = createTempFile(context, imageUri)
|
||||
val imagePath = tempFile?.path
|
||||
if (imagePath != null) {
|
||||
val v2TIMMessage = V2TIMManager.getMessageManager().createImageMessage(imagePath)
|
||||
V2TIMManager.getMessageManager().sendMessage(
|
||||
v2TIMMessage,
|
||||
userProfile?.trtcUserId!!,
|
||||
null,
|
||||
V2TIMMessage.V2TIM_PRIORITY_NORMAL,
|
||||
false,
|
||||
null,
|
||||
object : V2TIMSendCallback<V2TIMMessage> {
|
||||
override fun onProgress(p0: Int) {
|
||||
Log.d("ChatViewModel", "send image message progress: $p0")
|
||||
val imageMessage = OpenIMClient.getInstance().messageManager.createImageMessageFromFullPath(imagePath)
|
||||
|
||||
OpenIMClient.getInstance().messageManager.sendMessage(
|
||||
object : OnMsgSendCallback {
|
||||
override fun onProgress(progress: Long) {
|
||||
Log.d("ChatViewModel", "send image message progress: $progress")
|
||||
}
|
||||
|
||||
override fun onError(p0: Int, p1: String?) {
|
||||
Log.e("ChatViewModel", "send image message error: $p1")
|
||||
override fun onError(code: Int, error: String?) {
|
||||
Log.e("ChatViewModel", "send image message error: $error")
|
||||
}
|
||||
|
||||
override fun onSuccess(p0: V2TIMMessage?) {
|
||||
override fun onSuccess(data: Message?) {
|
||||
Log.d("ChatViewModel", "send image message success")
|
||||
val chatItem = ChatItem.convertToChatItem(p0!!, context, avatar = myProfile?.avatar)
|
||||
chatItem?.let {
|
||||
chatData = listOf(it) + chatData
|
||||
goToNew = true
|
||||
data?.let { sentMessage ->
|
||||
val chatItem = ChatItem.convertToChatItem(sentMessage, context, avatar = myProfile?.avatar)
|
||||
chatItem?.let {
|
||||
chatData = listOf(it) + chatData
|
||||
goToNew = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
imageMessage,
|
||||
userProfile?.trtcUserId!!, // recvID
|
||||
null, // groupID
|
||||
null // offlinePushInfo
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun createTempFile(context: Context, uri: Uri): File? {
|
||||
@@ -235,30 +262,34 @@ class ChatViewModel(
|
||||
}
|
||||
|
||||
fun fetchHistoryMessage(context: Context) {
|
||||
V2TIMManager.getMessageManager().getC2CHistoryMessageList(
|
||||
userProfile?.trtcUserId!!,
|
||||
20,
|
||||
null,
|
||||
object : V2TIMValueCallback<List<V2TIMMessage>> {
|
||||
override fun onSuccess(p0: List<V2TIMMessage>?) {
|
||||
chatData = (p0 ?: emptyList()).mapNotNull {
|
||||
val conversationID = "single_${userProfile?.trtcUserId!!}"
|
||||
|
||||
OpenIMClient.getInstance().messageManager.getAdvancedHistoryMessageList(
|
||||
object : OnBase<AdvancedMessage> {
|
||||
override fun onSuccess(data: AdvancedMessage?) {
|
||||
val messages = data?.messageList ?: emptyList()
|
||||
chatData = messages.mapNotNull {
|
||||
var avatar = userProfile?.avatar
|
||||
if (it.isSelf) {
|
||||
if (it.sendID == com.aiosman.ravenow.AppState.profile?.trtcUserId) {
|
||||
avatar = myProfile?.avatar
|
||||
}
|
||||
ChatItem.convertToChatItem(it, context,avatar)
|
||||
ChatItem.convertToChatItem(it, context, avatar)
|
||||
}
|
||||
if ((p0?.size ?: 0) < 20) {
|
||||
if (messages.size < 20) {
|
||||
hasMore = false
|
||||
}
|
||||
lastMessage = p0?.lastOrNull()
|
||||
lastMessage = messages.lastOrNull()
|
||||
Log.d("ChatViewModel", "fetch history message success")
|
||||
}
|
||||
|
||||
override fun onError(p0: Int, p1: String?) {
|
||||
Log.e("ChatViewModel", "fetch history message error: $p1")
|
||||
override fun onError(code: Int, error: String?) {
|
||||
Log.e("ChatViewModel", "fetch history message error: $error")
|
||||
}
|
||||
}
|
||||
},
|
||||
conversationID,
|
||||
null,
|
||||
20,
|
||||
ViewType.History
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,8 @@ import com.aiosman.ravenow.ui.composables.StatusBarSpacer
|
||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
import com.aiosman.ravenow.ui.navigateToGroupInfo
|
||||
import com.aiosman.ravenow.utils.NetworkUtils
|
||||
import com.tencent.imsdk.v2.V2TIMMessage
|
||||
// 临时兼容层 - TODO: 完成 OpenIM 迁移后删除
|
||||
import io.openim.android.sdk.enums.MessageType
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.UUID
|
||||
|
||||
@@ -376,18 +377,18 @@ fun GroupChatSelfItem(item: ChatItem) {
|
||||
modifier = Modifier
|
||||
.widthIn(
|
||||
min = 20.dp,
|
||||
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
||||
max = (if (item.messageType == MessageType.TEXT) 250.dp else 150.dp)
|
||||
)
|
||||
.clip(RoundedCornerShape(20.dp))
|
||||
.background(Color(0xFF6246FF))
|
||||
.padding(
|
||||
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
||||
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
||||
vertical = (if (item.messageType == MessageType.TEXT) 8.dp else 0.dp),
|
||||
horizontal = (if (item.messageType == MessageType.TEXT) 16.dp else 0.dp)
|
||||
)
|
||||
|
||||
) {
|
||||
when (item.messageType) {
|
||||
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
||||
MessageType.TEXT -> {
|
||||
Text(
|
||||
text = item.message,
|
||||
style = TextStyle(
|
||||
@@ -398,7 +399,7 @@ fun GroupChatSelfItem(item: ChatItem) {
|
||||
)
|
||||
}
|
||||
|
||||
V2TIMMessage.V2TIM_ELEM_TYPE_IMAGE -> {
|
||||
MessageType.PICTURE -> {
|
||||
CustomAsyncImage(
|
||||
imageUrl = item.imageList[1].url,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
@@ -469,17 +470,17 @@ fun GroupChatOtherItem(item: ChatItem, showAvatarAndNickname: Boolean = true) {
|
||||
modifier = Modifier
|
||||
.widthIn(
|
||||
min = 20.dp,
|
||||
max = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 250.dp else 150.dp)
|
||||
max = (if (item.messageType == MessageType.TEXT) 250.dp else 150.dp)
|
||||
)
|
||||
.clip(RoundedCornerShape(20.dp))
|
||||
.background(AppColors.bubbleBackground)
|
||||
.padding(
|
||||
vertical = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 8.dp else 0.dp),
|
||||
horizontal = (if (item.messageType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) 16.dp else 0.dp)
|
||||
vertical = (if (item.messageType == MessageType.TEXT) 8.dp else 0.dp),
|
||||
horizontal = (if (item.messageType == MessageType.TEXT) 16.dp else 0.dp)
|
||||
)
|
||||
) {
|
||||
when (item.messageType) {
|
||||
V2TIMMessage.V2TIM_ELEM_TYPE_TEXT -> {
|
||||
MessageType.TEXT -> {
|
||||
Text(
|
||||
text = item.message,
|
||||
style = TextStyle(
|
||||
@@ -490,7 +491,7 @@ fun GroupChatOtherItem(item: ChatItem, showAvatarAndNickname: Boolean = true) {
|
||||
)
|
||||
}
|
||||
|
||||
V2TIMMessage.V2TIM_ELEM_TYPE_IMAGE -> {
|
||||
MessageType.PICTURE -> {
|
||||
CustomAsyncImage(
|
||||
imageUrl = item.imageList[1].url,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
|
||||
@@ -22,12 +22,13 @@ import com.aiosman.ravenow.data.api.SingleChatRequestBody
|
||||
import com.aiosman.ravenow.entity.AccountProfileEntity
|
||||
import com.aiosman.ravenow.entity.ChatItem
|
||||
import com.aiosman.ravenow.entity.ChatNotification
|
||||
import com.tencent.imsdk.v2.V2TIMAdvancedMsgListener
|
||||
import com.tencent.imsdk.v2.V2TIMCallback
|
||||
import com.tencent.imsdk.v2.V2TIMManager
|
||||
import com.tencent.imsdk.v2.V2TIMMessage
|
||||
import com.tencent.imsdk.v2.V2TIMSendCallback
|
||||
import com.tencent.imsdk.v2.V2TIMValueCallback
|
||||
// OpenIM SDK 导入
|
||||
import io.openim.android.sdk.OpenIMClient
|
||||
import io.openim.android.sdk.enums.ViewType
|
||||
import io.openim.android.sdk.listener.OnAdvanceMsgListener
|
||||
import io.openim.android.sdk.listener.OnBase
|
||||
import io.openim.android.sdk.listener.OnMsgSendCallback
|
||||
import io.openim.android.sdk.models.*
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
@@ -43,10 +44,10 @@ class GroupChatViewModel(
|
||||
var myProfile by mutableStateOf<AccountProfileEntity?>(null)
|
||||
val userService: UserService = UserServiceImpl()
|
||||
val accountService: AccountService = AccountServiceImpl()
|
||||
var textMessageListener: V2TIMAdvancedMsgListener? = null
|
||||
var textMessageListener: OnAdvanceMsgListener? = null
|
||||
var hasMore by mutableStateOf(true)
|
||||
var isLoading by mutableStateOf(false)
|
||||
var lastMessage: V2TIMMessage? = null
|
||||
var lastMessage: Message? = null
|
||||
val showTimestampMap = mutableMapOf<String, Boolean>()
|
||||
var goToNew by mutableStateOf(false)
|
||||
|
||||
@@ -91,10 +92,16 @@ class GroupChatViewModel(
|
||||
}
|
||||
|
||||
fun RegistListener(context: Context) {
|
||||
textMessageListener = object : V2TIMAdvancedMsgListener() {
|
||||
override fun onRecvNewMessage(msg: V2TIMMessage?) {
|
||||
super.onRecvNewMessage(msg)
|
||||
// 检查 OpenIM 是否已登录
|
||||
if (!com.aiosman.ravenow.AppState.enableChat) {
|
||||
android.util.Log.w("GroupChatViewModel", "OpenIM 未登录,跳过注册消息监听器")
|
||||
return
|
||||
}
|
||||
|
||||
textMessageListener = object : OnAdvanceMsgListener {
|
||||
override fun onRecvNewMessage(msg: Message?) {
|
||||
msg?.let {
|
||||
// 检查是否是当前群聊的消息
|
||||
if (it.groupID == groupId) {
|
||||
val chatItem = ChatItem.convertToChatItem(msg, context, avatar = null)
|
||||
chatItem?.let {
|
||||
@@ -105,79 +112,98 @@ class GroupChatViewModel(
|
||||
}
|
||||
}
|
||||
}
|
||||
V2TIMManager.getMessageManager().addAdvancedMsgListener(textMessageListener)
|
||||
OpenIMClient.getInstance().messageManager.setAdvancedMsgListener(textMessageListener)
|
||||
}
|
||||
|
||||
fun UnRegistListener() {
|
||||
V2TIMManager.getMessageManager().removeAdvancedMsgListener(textMessageListener)
|
||||
// OpenIM SDK 不需要显式移除监听器,只需要设置为 null
|
||||
textMessageListener = null
|
||||
}
|
||||
|
||||
fun clearUnRead() {
|
||||
val conversationID = "group_${groupId}"
|
||||
V2TIMManager.getConversationManager()
|
||||
.cleanConversationUnreadMessageCount(conversationID, 0, 0, object : V2TIMCallback {
|
||||
override fun onSuccess() {
|
||||
Log.i("imsdk", "清除群聊未读消息成功")
|
||||
OpenIMClient.getInstance().messageManager.markConversationMessageAsRead(
|
||||
conversationID,
|
||||
object : OnBase<String> {
|
||||
override fun onSuccess(data: String?) {
|
||||
Log.i("openim", "清除群聊未读消息成功")
|
||||
}
|
||||
|
||||
override fun onError(code: Int, desc: String) {
|
||||
Log.i("imsdk", "清除群聊未读消息失败, code:$code, desc:$desc")
|
||||
override fun onError(code: Int, error: String?) {
|
||||
Log.i("openim", "清除群聊未读消息失败, code:$code, error:$error")
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun onLoadMore(context: Context) {
|
||||
if (!hasMore || isLoading) return
|
||||
isLoading = true
|
||||
viewModelScope.launch {
|
||||
V2TIMManager.getMessageManager().getGroupHistoryMessageList(
|
||||
groupId,
|
||||
20,
|
||||
lastMessage,
|
||||
object : V2TIMValueCallback<List<V2TIMMessage>> {
|
||||
override fun onSuccess(p0: List<V2TIMMessage>?) {
|
||||
chatData = chatData + (p0 ?: emptyList()).map {
|
||||
val conversationID = "group_${groupId}"
|
||||
|
||||
OpenIMClient.getInstance().messageManager.getAdvancedHistoryMessageList(
|
||||
object : OnBase<AdvancedMessage> {
|
||||
override fun onSuccess(data: AdvancedMessage?) {
|
||||
val messages = data?.messageList ?: emptyList()
|
||||
chatData = chatData + messages.map {
|
||||
ChatItem.convertToChatItem(it, context, avatar = null)
|
||||
}.filterNotNull()
|
||||
if ((p0?.size ?: 0) < 20) {
|
||||
|
||||
if (messages.size < 20) {
|
||||
hasMore = false
|
||||
}
|
||||
lastMessage = p0?.lastOrNull()
|
||||
lastMessage = messages.lastOrNull()
|
||||
isLoading = false
|
||||
}
|
||||
|
||||
override fun onError(p0: Int, p1: String?) {
|
||||
Log.e("GroupChatViewModel", "获取群聊历史消息失败: $p1")
|
||||
override fun onError(code: Int, error: String?) {
|
||||
Log.e("GroupChatViewModel", "获取群聊历史消息失败: $error")
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
},
|
||||
conversationID,
|
||||
lastMessage,
|
||||
20,
|
||||
ViewType.History
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun sendMessage(message: String, context: Context) {
|
||||
val v2TIMMessage = V2TIMManager.getMessageManager().createTextMessage(message)
|
||||
V2TIMManager.getMessageManager().sendMessage(
|
||||
v2TIMMessage,
|
||||
null,
|
||||
groupId,
|
||||
V2TIMMessage.V2TIM_PRIORITY_NORMAL,
|
||||
false,
|
||||
null,
|
||||
object : V2TIMSendCallback<V2TIMMessage> {
|
||||
override fun onProgress(p0: Int) {}
|
||||
override fun onError(p0: Int, p1: String?) {
|
||||
Log.e("GroupChatViewModel", "发送群聊消息失败: $p1")
|
||||
// 检查 OpenIM 是否已登录
|
||||
if (!com.aiosman.ravenow.AppState.enableChat) {
|
||||
android.util.Log.w("GroupChatViewModel", "OpenIM 未登录,无法发送消息")
|
||||
return
|
||||
}
|
||||
|
||||
val textMessage = OpenIMClient.getInstance().messageManager.createTextMessage(message)
|
||||
|
||||
OpenIMClient.getInstance().messageManager.sendMessage(
|
||||
object : OnMsgSendCallback {
|
||||
override fun onProgress(progress: Long) {
|
||||
// 发送进度
|
||||
}
|
||||
override fun onSuccess(p0: V2TIMMessage?) {
|
||||
|
||||
override fun onError(code: Int, error: String?) {
|
||||
Log.e("GroupChatViewModel", "发送群聊消息失败: $error")
|
||||
}
|
||||
|
||||
override fun onSuccess(data: Message?) {
|
||||
sendChatAiMessage(message = message, trtcGroupId = groupId)
|
||||
val chatItem = ChatItem.convertToChatItem(p0!!, context, avatar = myProfile?.avatar)
|
||||
chatItem?.let {
|
||||
chatData = listOf(it) + chatData
|
||||
goToNew = true
|
||||
data?.let { sentMessage ->
|
||||
val chatItem = ChatItem.convertToChatItem(sentMessage, context, avatar = myProfile?.avatar)
|
||||
chatItem?.let {
|
||||
chatData = listOf(it) + chatData
|
||||
goToNew = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
textMessage,
|
||||
null, // recvID (群聊为 null)
|
||||
groupId, // groupID
|
||||
null // offlinePushInfo
|
||||
)
|
||||
}
|
||||
|
||||
@@ -197,27 +223,32 @@ class GroupChatViewModel(
|
||||
val tempFile = createTempFile(context, imageUri)
|
||||
val imagePath = tempFile?.path
|
||||
if (imagePath != null) {
|
||||
val v2TIMMessage = V2TIMManager.getMessageManager().createImageMessage(imagePath)
|
||||
V2TIMManager.getMessageManager().sendMessage(
|
||||
v2TIMMessage,
|
||||
groupId,
|
||||
null,
|
||||
V2TIMMessage.V2TIM_PRIORITY_NORMAL,
|
||||
false,
|
||||
null,
|
||||
object : V2TIMSendCallback<V2TIMMessage> {
|
||||
override fun onProgress(p0: Int) {}
|
||||
override fun onError(p0: Int, p1: String?) {
|
||||
Log.e("GroupChatViewModel", "发送群聊图片消息失败: $p1")
|
||||
val imageMessage = OpenIMClient.getInstance().messageManager.createImageMessageFromFullPath(imagePath)
|
||||
|
||||
OpenIMClient.getInstance().messageManager.sendMessage(
|
||||
object : OnMsgSendCallback {
|
||||
override fun onProgress(progress: Long) {
|
||||
Log.d("GroupChatViewModel", "发送群聊图片消息进度: $progress")
|
||||
}
|
||||
override fun onSuccess(p0: V2TIMMessage?) {
|
||||
val chatItem = ChatItem.convertToChatItem(p0!!, context, avatar = myProfile?.avatar)
|
||||
chatItem?.let {
|
||||
chatData = listOf(it) + chatData
|
||||
goToNew = true
|
||||
|
||||
override fun onError(code: Int, error: String?) {
|
||||
Log.e("GroupChatViewModel", "发送群聊图片消息失败: $error")
|
||||
}
|
||||
|
||||
override fun onSuccess(data: Message?) {
|
||||
data?.let { sentMessage ->
|
||||
val chatItem = ChatItem.convertToChatItem(sentMessage, context, avatar = myProfile?.avatar)
|
||||
chatItem?.let {
|
||||
chatData = listOf(it) + chatData
|
||||
goToNew = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
imageMessage,
|
||||
null, // recvID (群聊为 null)
|
||||
groupId, // groupID
|
||||
null // offlinePushInfo
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -254,25 +285,29 @@ class GroupChatViewModel(
|
||||
}
|
||||
|
||||
fun fetchHistoryMessage(context: Context) {
|
||||
V2TIMManager.getMessageManager().getGroupHistoryMessageList(
|
||||
groupId,
|
||||
20,
|
||||
null,
|
||||
object : V2TIMValueCallback<List<V2TIMMessage>> {
|
||||
override fun onSuccess(p0: List<V2TIMMessage>?) {
|
||||
chatData = (p0 ?: emptyList()).mapNotNull {
|
||||
val conversationID = "group_${groupId}"
|
||||
|
||||
OpenIMClient.getInstance().messageManager.getAdvancedHistoryMessageList(
|
||||
object : OnBase<AdvancedMessage> {
|
||||
override fun onSuccess(data: AdvancedMessage?) {
|
||||
val messages = data?.messageList ?: emptyList()
|
||||
chatData = messages.mapNotNull {
|
||||
ChatItem.convertToChatItem(it, context, avatar = null)
|
||||
}
|
||||
if ((p0?.size ?: 0) < 20) {
|
||||
if (messages.size < 20) {
|
||||
hasMore = false
|
||||
}
|
||||
lastMessage = p0?.lastOrNull()
|
||||
lastMessage = messages.lastOrNull()
|
||||
}
|
||||
|
||||
override fun onError(p0: Int, p1: String?) {
|
||||
Log.e("GroupChatViewModel", "获取群聊历史消息失败: $p1")
|
||||
override fun onError(code: Int, error: String?) {
|
||||
Log.e("GroupChatViewModel", "获取群聊历史消息失败: $error")
|
||||
}
|
||||
}
|
||||
},
|
||||
conversationID,
|
||||
null,
|
||||
20,
|
||||
ViewType.History
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user