import Foundation import GRDB import Martin enum MessageType: String, Codable, DatabaseValueConvertible { case chat case groupchat case error } enum MessageContentType: Codable & Equatable, DatabaseValueConvertible { case text case typing } enum MessageStatus: Int, Codable, DatabaseValueConvertible { case pending case sent case error } struct Message: DBStorable, Equatable { static let databaseTableName = "messages" let id: String let type: MessageType let date: Date let contentType: MessageContentType let status: MessageStatus let from: String let to: String? let body: String? let subject: String? let thread: String? let oobUrl: String? } extension Message { static func map(from martinMessage: Martin.Message) -> Message? { #if DEBUG print("---") print("Message received: \(martinMessage)") print("---") #endif // Check that the message type is supported let chatTypes: [StanzaType] = [.chat, .groupchat] guard let mType = martinMessage.type, chatTypes.contains(mType) else { #if DEBUG print("Unsupported message type: \(martinMessage.type?.rawValue ?? "nil")") #endif return nil } // Type let type = MessageType(rawValue: martinMessage.type?.rawValue ?? "") ?? .chat // Content type var contentType: MessageContentType = .text if martinMessage.hints.contains(.noStore) { contentType = .typing } // From/To let from = martinMessage.from?.bareJid.stringValue ?? "" let to = martinMessage.to?.bareJid.stringValue // Extract date or set current var date = Date() if let timestampStr = martinMessage.attribute("archived_date"), let timeInterval = TimeInterval(timestampStr) { date = Date(timeIntervalSince1970: timeInterval) } // Msg let msg = Message( id: martinMessage.id ?? UUID().uuidString, type: type, date: date, contentType: contentType, status: .sent, from: from, to: to, body: martinMessage.body, subject: martinMessage.subject, thread: martinMessage.thread, oobUrl: martinMessage.oob ) return msg } }