migrate persistence from JSON to SwiftData
Models: - Convert Conversation and ChatMessage to SwiftData @Model classes with a one-to-many relationship and cascade delete. - Rename ChatMessage.id to clientID and drop Conversation.id in favor of jid (the string id would clash with PersistentIdentifier). - Keep MessageReaction as a Codable value stored in an array attribute. Persistence: - Add ArchiveStore, a per-account ModelContainer/ModelContext that replaces the JSON ChatArchive with load/save/erase. - Add ArchiveMetadataRecord for the durable MAM checkpoints, cursor, locally deleted message IDs and roster contact JIDs. - Add LegacyArchiveImporter to import the old JSON snapshot once and delete the file afterwards, preserving existing history. AppModel: - Replace ChatArchive with ArchiveStore and persist via context.save(); insert new models and delete the replaced object on upsert merges so SwiftData never keeps an orphaned duplicate. Tests: - Replace ChatArchiveTests with ArchiveStoreTests (store round-trip and legacy import) and drop the now-obsolete Codable round-trip assertions.
This commit is contained in:
1 parent
0317277d46
commit
cbb820a86e
30 files changed
+726
-665
No files matched your search
@@ -129,7 +129,7 @@ struct AudioMessagePlayer: View {
|
||||
}
|
||||
|
||||
private var isCurrent: Bool {
|
||||
playback.currentMessageID == message.id
|
||||
playback.currentMessageID == message.clientID
|
||||
}
|
||||
|
||||
private var isPlaying: Bool {
|
||||
@@ -194,7 +194,7 @@ struct AudioMessagePlayer: View {
|
||||
return
|
||||
}
|
||||
playback.toggle(
|
||||
messageID: message.id,
|
||||
messageID: message.clientID,
|
||||
url: downloadedURL,
|
||||
durationHint: message.duration,
|
||||
isVoice: message.kind == .voice
|
||||
@@ -203,7 +203,7 @@ struct AudioMessagePlayer: View {
|
||||
return
|
||||
}
|
||||
playback.toggle(
|
||||
messageID: message.id,
|
||||
messageID: message.clientID,
|
||||
url: localURL,
|
||||
durationHint: message.duration,
|
||||
isVoice: message.kind == .voice
|
||||
@@ -213,7 +213,7 @@ struct AudioMessagePlayer: View {
|
||||
private func seek(_ fraction: Double) {
|
||||
guard let localURL else { return }
|
||||
playback.seek(
|
||||
messageID: message.id,
|
||||
messageID: message.clientID,
|
||||
url: localURL,
|
||||
durationHint: message.duration,
|
||||
isVoice: message.kind == .voice,
|
||||
|
||||
@@ -124,7 +124,7 @@ struct PhotoAttachmentPreview: View {
|
||||
private func openViewer() {
|
||||
Task {
|
||||
await model.presentMediaViewer(message)
|
||||
if model.mediaViewerItem?.id != message.id,
|
||||
if model.mediaViewerItem?.id != message.clientID,
|
||||
message.remoteAttachmentURL == nil {
|
||||
onFallbackTap()
|
||||
}
|
||||
|
||||
@@ -112,10 +112,10 @@ struct ReplyThreadOverlay: View {
|
||||
model: model,
|
||||
message: reply,
|
||||
maximumBubbleWidth: maximumBubbleWidth,
|
||||
isSelected: reply.id == selectedReplyID,
|
||||
showsDeliveryStatus: reply.id == selectedReplyID
|
||||
isSelected: reply.clientID == selectedReplyID,
|
||||
showsDeliveryStatus: reply.clientID == selectedReplyID
|
||||
)
|
||||
.id(reply.id)
|
||||
.id(reply.clientID)
|
||||
}
|
||||
}
|
||||
.padding(.leading, showsBracket && bracketOnLeadingEdge ? 43 : 0)
|
||||
|
||||
@@ -142,7 +142,7 @@ struct VideoAttachmentPreview: View {
|
||||
private func openViewer() {
|
||||
Task {
|
||||
await model.presentMediaViewer(message)
|
||||
if model.mediaViewerItem?.id != message.id,
|
||||
if model.mediaViewerItem?.id != message.clientID,
|
||||
message.remoteAttachmentURL == nil {
|
||||
onFallbackTap()
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ struct VideoNotePreview: View {
|
||||
}
|
||||
.onReceive(NotificationCenter.default.publisher(for: .lumaExclusiveMediaPlayback)) { notification in
|
||||
guard let activeID = notification.object as? String,
|
||||
activeID != message.id else { return }
|
||||
activeID != message.clientID else { return }
|
||||
player?.pause()
|
||||
isPlaying = false
|
||||
}
|
||||
@@ -146,7 +146,7 @@ struct VideoNotePreview: View {
|
||||
model.audioPlayback.stop()
|
||||
NotificationCenter.default.post(
|
||||
name: .lumaExclusiveMediaPlayback,
|
||||
object: message.id
|
||||
object: message.clientID
|
||||
)
|
||||
player.play()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user