KasztelanKarta/Kasztelan/MessageStore.swift
2026-10-16 23:37:49 +01:00

64 lines
2.4 KiB
Swift

import Foundation
final class MessageStore {
private let messagesKey = "kasztelan.messages"
private let lastIDKey = "kasztelan.messages.lastID"
private let installedAtKey = "kasztelan.installation.timestamp"
var messages: [KasztelanMessage] {
guard let data = UserDefaults.standard.data(forKey: messagesKey),
let values = try? JSONDecoder().decode([KasztelanMessage].self, from: data) else { return [] }
return values.filter(isFromThisInstallation).sorted { $0.id > $1.id }
}
var lastServerID: Int { UserDefaults.standard.integer(forKey: lastIDKey) }
@discardableResult
func merge(_ incoming: [KasztelanMessage]) -> [KasztelanMessage] {
var saved = messages
var ids = Set(saved.map(\.id))
let previousLast = lastServerID
let added = incoming.filter { message in
guard message.id > 0,
isFromThisInstallation(message),
!message.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return false }
return ids.insert(message.id).inserted
}
saved.append(contentsOf: added)
saved.sort { $0.id > $1.id }
saved = Array(saved.prefix(100))
persist(saved, lastID: max(previousLast, incoming.map(\.id).max() ?? 0))
return added.filter { $0.id > previousLast }.sorted { $0.id > $1.id }
}
func delete(id: Int) {
persist(messages.filter { $0.id != id }, lastID: lastServerID)
}
func clear() {
UserDefaults.standard.removeObject(forKey: messagesKey)
UserDefaults.standard.removeObject(forKey: lastIDKey)
}
private func persist(_ messages: [KasztelanMessage], lastID: Int) {
if let data = try? JSONEncoder().encode(messages) {
UserDefaults.standard.set(data, forKey: messagesKey)
}
UserDefaults.standard.set(lastID, forKey: lastIDKey)
}
private var installedAt: Int {
let saved = UserDefaults.standard.integer(forKey: installedAtKey)
if saved > 0 { return saved }
let created = (try? FileManager.default.attributesOfItem(atPath: NSHomeDirectory())[.creationDate] as? Date)
?? Date()
let timestamp = Int(created.timeIntervalSince1970)
UserDefaults.standard.set(timestamp, forKey: installedAtKey)
return timestamp
}
private func isFromThisInstallation(_ message: KasztelanMessage) -> Bool {
message.sentAt >= installedAt
}
}