- 添加 expiresAt 和 refreshUserSig 参数支持自动续签 - 修改 PushSDK 初始化方式,自动完成设备注册和厂商初始化 - 调整过期续签策略,从提前 15 分钟改为提前 5 分钟触发 - 重构 RN SDK 文档结构,简化安装和使用方式 - 更新统一登录流程,支持 profile 信息传递 - 添加 IM 数据库自动隔离功能 - 修复 Android 群消息聚合问题 - 补充自动化测试验证和错误处理机制
146 行
4.1 KiB
Swift
146 行
4.1 KiB
Swift
import Foundation
|
|
import XuqmSDK
|
|
|
|
@MainActor
|
|
final class ChatViewModel: ObservableObject {
|
|
@Published var messages: [ImMessage] = []
|
|
@Published var inputText: String = ""
|
|
@Published var isLoading: Bool = false
|
|
@Published var errorMessage: String?
|
|
@Published var connectionStatus: String = "连接中"
|
|
|
|
private var targetId: String = ""
|
|
private var chatType: ChatType = .single
|
|
private var currentPage = 0
|
|
private let pageSize = 20
|
|
private var hasMore = true
|
|
private var isLoadingMore = false
|
|
|
|
private var delegateBridge: ChatEventDelegateBridge?
|
|
|
|
func setup(targetId: String, chatType: ChatType) {
|
|
self.targetId = targetId
|
|
self.chatType = chatType
|
|
self.messages = []
|
|
self.currentPage = 0
|
|
self.hasMore = true
|
|
self.isLoadingMore = false
|
|
self.errorMessage = nil
|
|
|
|
let bridge = ChatEventDelegateBridge(viewModel: self)
|
|
self.delegateBridge = bridge
|
|
ImSDK.shared.setDelegate(bridge)
|
|
|
|
loadHistory()
|
|
}
|
|
|
|
func loadHistory() {
|
|
guard !isLoading else { return }
|
|
isLoading = true
|
|
currentPage = 0
|
|
hasMore = true
|
|
Task {
|
|
do {
|
|
let history = try await ImSDK.shared.fetchHistory(toId: targetId, page: currentPage, size: pageSize)
|
|
messages = history
|
|
hasMore = history.count >= pageSize
|
|
isLoading = false
|
|
} catch {
|
|
errorMessage = error.localizedDescription
|
|
isLoading = false
|
|
}
|
|
}
|
|
}
|
|
|
|
func loadMoreHistory() {
|
|
guard hasMore, !isLoadingMore, !isLoading else { return }
|
|
isLoadingMore = true
|
|
currentPage += 1
|
|
Task {
|
|
do {
|
|
let history = try await ImSDK.shared.fetchHistory(toId: targetId, page: currentPage, size: pageSize)
|
|
messages.append(contentsOf: history)
|
|
hasMore = history.count >= pageSize
|
|
isLoadingMore = false
|
|
} catch {
|
|
isLoadingMore = false
|
|
}
|
|
}
|
|
}
|
|
|
|
func sendText() {
|
|
let text = inputText.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
guard !text.isEmpty else { return }
|
|
let message = ImSDK.shared.sendTextMessage(toId: targetId, chatType: chatType, content: text)
|
|
messages.insert(message, at: 0)
|
|
inputText = ""
|
|
}
|
|
|
|
func markRead() {
|
|
Task {
|
|
try? await ImSDK.shared.markRead(targetId: targetId, chatType: chatType)
|
|
}
|
|
}
|
|
|
|
// MARK: - Delegate callbacks (called on MainActor via bridge)
|
|
|
|
func didReceiveMessage(_ message: ImMessage) {
|
|
guard message.fromId == targetId || message.toId == targetId else { return }
|
|
if !messages.contains(where: { $0.id == message.id }) {
|
|
messages.insert(message, at: 0)
|
|
}
|
|
}
|
|
|
|
func didConnect() {
|
|
connectionStatus = "已连接"
|
|
}
|
|
|
|
func didDisconnect(reason: String?) {
|
|
connectionStatus = reason ?? "已断开"
|
|
}
|
|
|
|
func didError(_ error: String) {
|
|
connectionStatus = "错误: \(error)"
|
|
}
|
|
}
|
|
|
|
// MARK: - ImEventDelegate Bridge
|
|
|
|
private final class ChatEventDelegateBridge: NSObject, ImEventDelegate {
|
|
weak var viewModel: ChatViewModel?
|
|
|
|
init(viewModel: ChatViewModel) {
|
|
self.viewModel = viewModel
|
|
}
|
|
|
|
func imClientDidConnect() {
|
|
Task { @MainActor [weak viewModel] in
|
|
viewModel?.didConnect()
|
|
}
|
|
}
|
|
|
|
func imClientDidDisconnect(reason: String?) {
|
|
Task { @MainActor [weak viewModel] in
|
|
viewModel?.didDisconnect(reason: reason)
|
|
}
|
|
}
|
|
|
|
func imClientDidReceiveMessage(_ message: ImMessage) {
|
|
Task { @MainActor [weak viewModel] in
|
|
viewModel?.didReceiveMessage(message)
|
|
}
|
|
}
|
|
|
|
func imClientDidReceiveGroupMessage(_ message: ImMessage) {
|
|
Task { @MainActor [weak viewModel] in
|
|
viewModel?.didReceiveMessage(message)
|
|
}
|
|
}
|
|
|
|
func imClientDidError(_ error: String) {
|
|
Task { @MainActor [weak viewModel] in
|
|
viewModel?.didError(error)
|
|
}
|
|
}
|
|
}
|