XuqmGroup-iOSSDK/XuqmDemo/Sources/ViewModels/ChatViewModel.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)
}
}
}