2026-04-21 22:07:29 +08:00
|
|
|
package com.xuqm.sdk.im
|
|
|
|
|
|
2026-04-27 19:23:11 +08:00
|
|
|
import com.xuqm.sdk.XuqmLoginSession
|
2026-04-21 22:07:29 +08:00
|
|
|
import com.xuqm.sdk.XuqmSDK
|
2026-04-27 19:30:06 +08:00
|
|
|
import com.xuqm.sdk.core.ServiceEndpointRegistry
|
2026-04-27 17:18:55 +08:00
|
|
|
import com.xuqm.sdk.im.api.AddMemberRequest
|
|
|
|
|
import com.xuqm.sdk.im.api.CreateGroupRequest
|
2026-04-21 22:07:29 +08:00
|
|
|
import com.xuqm.sdk.im.api.ImApi
|
2026-04-27 17:18:55 +08:00
|
|
|
import com.xuqm.sdk.im.api.SetMutedRequest
|
|
|
|
|
import com.xuqm.sdk.im.api.SetPinnedRequest
|
|
|
|
|
import com.xuqm.sdk.im.api.UpdateGroupRequest
|
2026-04-21 22:07:29 +08:00
|
|
|
import com.xuqm.sdk.im.listener.ImEventListener
|
2026-04-27 19:41:26 +08:00
|
|
|
import com.xuqm.sdk.im.model.ImConnectionState
|
2026-04-27 17:18:55 +08:00
|
|
|
import com.xuqm.sdk.im.model.ConversationData
|
|
|
|
|
import com.xuqm.sdk.im.model.ImGroup
|
|
|
|
|
import com.xuqm.sdk.im.model.ImMessage
|
2026-04-21 22:07:29 +08:00
|
|
|
import com.xuqm.sdk.network.ApiClient
|
|
|
|
|
import kotlinx.coroutines.Dispatchers
|
2026-04-27 17:18:55 +08:00
|
|
|
import kotlinx.coroutines.withContext
|
2026-04-27 19:41:26 +08:00
|
|
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
|
|
|
import kotlinx.coroutines.flow.StateFlow
|
2026-04-21 22:07:29 +08:00
|
|
|
|
|
|
|
|
object ImSDK {
|
|
|
|
|
|
|
|
|
|
private var client: ImClient? = null
|
2026-04-27 19:30:06 +08:00
|
|
|
private val api: ImApi get() = ApiClient.create(ImApi::class.java, ServiceEndpointRegistry.imApiBaseUrl)
|
2026-04-27 19:41:26 +08:00
|
|
|
private val connectionListener = object : ImEventListener {
|
|
|
|
|
override fun onConnected() {
|
|
|
|
|
_connectionState.value = ImConnectionState.Connected
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onDisconnected(reason: String?) {
|
|
|
|
|
_connectionState.value = ImConnectionState.Disconnected(reason)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onError(error: String) {
|
|
|
|
|
_connectionState.value = ImConnectionState.Disconnected(error)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
private val _connectionState = MutableStateFlow<ImConnectionState>(ImConnectionState.Disconnected("未连接"))
|
|
|
|
|
val connectionState: StateFlow<ImConnectionState> = _connectionState
|
2026-04-27 17:18:55 +08:00
|
|
|
|
|
|
|
|
var currentUserId: String = ""
|
|
|
|
|
private set
|
|
|
|
|
|
2026-04-27 19:23:11 +08:00
|
|
|
init {
|
|
|
|
|
XuqmSDK.currentLoginSession?.let { onSdkLogin(it) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
suspend fun login(
|
|
|
|
|
userId: String,
|
|
|
|
|
userSig: String,
|
|
|
|
|
nickname: String? = null,
|
|
|
|
|
avatar: String? = null,
|
|
|
|
|
) = withContext(Dispatchers.IO) {
|
|
|
|
|
XuqmSDK.requireInit()
|
|
|
|
|
currentUserId = userId
|
|
|
|
|
connectWithToken(userSig)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
suspend fun loginWithUserSig(userId: String, userSig: String) =
|
2026-04-27 17:18:55 +08:00
|
|
|
withContext(Dispatchers.IO) {
|
|
|
|
|
XuqmSDK.requireInit()
|
|
|
|
|
currentUserId = userId
|
2026-04-27 19:23:11 +08:00
|
|
|
connectWithToken(userSig)
|
2026-04-27 19:00:54 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-27 19:23:11 +08:00
|
|
|
@Deprecated("Use loginWithUserSig(userId, userSig) instead.")
|
2026-04-27 19:00:54 +08:00
|
|
|
suspend fun loginWithToken(userId: String, token: String) =
|
2026-04-27 19:23:11 +08:00
|
|
|
loginWithUserSig(userId, token)
|
2026-04-21 22:07:29 +08:00
|
|
|
|
2026-04-27 17:18:55 +08:00
|
|
|
fun sendMessage(toId: String, chatType: String, msgType: String, content: String) {
|
2026-04-21 22:07:29 +08:00
|
|
|
client?.sendMessage(toId, chatType, msgType, content)
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-27 17:18:55 +08:00
|
|
|
suspend fun fetchHistory(toId: String, page: Int = 0, size: Int = 20): List<ImMessage> =
|
|
|
|
|
withContext(Dispatchers.IO) {
|
2026-04-27 19:00:54 +08:00
|
|
|
api.fetchHistory(toId, XuqmSDK.appId, page, size).data ?: emptyList()
|
2026-04-27 17:18:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
suspend fun fetchGroupHistory(groupId: String, page: Int = 0, size: Int = 20): List<ImMessage> =
|
|
|
|
|
withContext(Dispatchers.IO) {
|
2026-04-27 19:00:54 +08:00
|
|
|
api.fetchGroupHistory(groupId, XuqmSDK.appId, page, size).data ?: emptyList()
|
2026-04-27 17:18:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
suspend fun listGroups(): List<ImGroup> =
|
2026-04-27 19:00:54 +08:00
|
|
|
withContext(Dispatchers.IO) { api.listGroups(XuqmSDK.appId).data ?: emptyList() }
|
2026-04-27 17:18:55 +08:00
|
|
|
|
|
|
|
|
suspend fun createGroup(name: String, memberIds: List<String>): ImGroup? =
|
2026-04-27 19:00:54 +08:00
|
|
|
withContext(Dispatchers.IO) { api.createGroup(XuqmSDK.appId, CreateGroupRequest(name, memberIds)).data }
|
2026-04-27 17:18:55 +08:00
|
|
|
|
|
|
|
|
suspend fun getGroupInfo(groupId: String): ImGroup? =
|
|
|
|
|
withContext(Dispatchers.IO) { api.getGroupInfo(groupId).data }
|
|
|
|
|
|
|
|
|
|
suspend fun updateGroupInfo(groupId: String, name: String? = null, announcement: String? = null) =
|
|
|
|
|
withContext(Dispatchers.IO) { api.updateGroupInfo(groupId, UpdateGroupRequest(name, announcement)) }
|
|
|
|
|
|
|
|
|
|
suspend fun addGroupMember(groupId: String, userId: String) =
|
|
|
|
|
withContext(Dispatchers.IO) { api.addGroupMember(groupId, AddMemberRequest(userId)) }
|
|
|
|
|
|
|
|
|
|
suspend fun removeGroupMember(groupId: String, userId: String) =
|
|
|
|
|
withContext(Dispatchers.IO) { api.removeGroupMember(groupId, userId) }
|
|
|
|
|
|
|
|
|
|
suspend fun leaveGroup(groupId: String) =
|
2026-04-27 19:00:54 +08:00
|
|
|
withContext(Dispatchers.IO) { api.removeGroupMember(groupId, currentUserId) }
|
2026-04-27 17:18:55 +08:00
|
|
|
|
2026-04-27 19:00:54 +08:00
|
|
|
suspend fun listFriends(): List<String> =
|
|
|
|
|
withContext(Dispatchers.IO) { api.listFriends(XuqmSDK.appId).data ?: emptyList() }
|
2026-04-27 17:18:55 +08:00
|
|
|
|
|
|
|
|
suspend fun addFriend(friendId: String) =
|
2026-04-27 19:00:54 +08:00
|
|
|
withContext(Dispatchers.IO) { api.addFriend(XuqmSDK.appId, friendId) }
|
2026-04-27 17:18:55 +08:00
|
|
|
|
|
|
|
|
suspend fun removeFriend(friendId: String) =
|
2026-04-27 19:00:54 +08:00
|
|
|
withContext(Dispatchers.IO) { api.removeFriend(friendId, XuqmSDK.appId) }
|
2026-04-27 17:18:55 +08:00
|
|
|
|
|
|
|
|
suspend fun listConversations(): List<ConversationData> =
|
2026-04-27 19:00:54 +08:00
|
|
|
withContext(Dispatchers.IO) { api.listConversations(XuqmSDK.appId).data ?: emptyList() }
|
2026-04-27 17:18:55 +08:00
|
|
|
|
|
|
|
|
suspend fun setConversationPinned(targetId: String, chatType: String, pinned: Boolean) =
|
|
|
|
|
withContext(Dispatchers.IO) {
|
|
|
|
|
api.setConversationPinned(targetId, chatType, SetPinnedRequest(pinned))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
suspend fun setConversationMuted(targetId: String, chatType: String, muted: Boolean) =
|
|
|
|
|
withContext(Dispatchers.IO) {
|
|
|
|
|
api.setConversationMuted(targetId, chatType, SetMutedRequest(muted))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
suspend fun markRead(targetId: String, chatType: String = "SINGLE") =
|
2026-04-27 19:00:54 +08:00
|
|
|
withContext(Dispatchers.IO) { api.markRead(targetId, XuqmSDK.appId, chatType) }
|
2026-04-27 17:18:55 +08:00
|
|
|
|
2026-04-21 22:07:29 +08:00
|
|
|
fun addListener(listener: ImEventListener) = client?.addListener(listener)
|
|
|
|
|
fun removeListener(listener: ImEventListener) = client?.removeListener(listener)
|
2026-04-27 17:18:55 +08:00
|
|
|
|
|
|
|
|
fun disconnect() {
|
2026-04-27 19:23:11 +08:00
|
|
|
disconnectInternal(clearTokenStore = true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun onSdkLogin(session: XuqmLoginSession) {
|
|
|
|
|
XuqmSDK.requireInit()
|
|
|
|
|
currentUserId = session.userId
|
|
|
|
|
connectWithToken(session.userSig)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun onSdkLogout() {
|
|
|
|
|
disconnectInternal(clearTokenStore = false)
|
2026-04-27 17:18:55 +08:00
|
|
|
}
|
2026-04-27 19:00:54 +08:00
|
|
|
|
|
|
|
|
private fun connectWithToken(token: String) {
|
|
|
|
|
XuqmSDK.tokenStore.saveToken(token)
|
|
|
|
|
client?.disconnect()
|
2026-04-27 19:41:26 +08:00
|
|
|
_connectionState.value = ImConnectionState.Connecting
|
2026-04-27 19:30:06 +08:00
|
|
|
client = ImClient(ServiceEndpointRegistry.imWsUrl, token, XuqmSDK.appId)
|
2026-04-27 19:41:26 +08:00
|
|
|
client?.addListener(connectionListener)
|
2026-04-27 19:00:54 +08:00
|
|
|
client?.connect()
|
|
|
|
|
}
|
2026-04-27 19:23:11 +08:00
|
|
|
|
|
|
|
|
private fun disconnectInternal(clearTokenStore: Boolean) {
|
|
|
|
|
client?.disconnect()
|
|
|
|
|
client = null
|
|
|
|
|
currentUserId = ""
|
2026-04-27 19:41:26 +08:00
|
|
|
_connectionState.value = ImConnectionState.Disconnected("已断开")
|
2026-04-27 19:23:11 +08:00
|
|
|
if (clearTokenStore) {
|
|
|
|
|
XuqmSDK.tokenStore.clear()
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-21 22:07:29 +08:00
|
|
|
}
|