XuqmGroup-iOSSDK/XuqmDemo/Sources/ViewModels/ChatViewModel.swift
XuqmGroup e7067d03cb feat(sdk): 更新 SDK 设计文档和 API 重构
- 添加 expiresAt 和 refreshUserSig 参数支持自动续签
- 修改 PushSDK 初始化方式,自动完成设备注册和厂商初始化
- 调整过期续签策略,从提前 15 分钟改为提前 5 分钟触发
- 重构 RN SDK 文档结构,简化安装和使用方式
- 更新统一登录流程,支持 profile 信息传递
- 添加 IM 数据库自动隔离功能
- 修复 Android 群消息聚合问题
- 补充自动化测试验证和错误处理机制
2026-05-01 21:27:39 +08:00

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)
}
}
}