Files
Luma/Sources/Shared/Services/ChatMediaImageCache.swift
T
wt cbb820a86e
iOS CI / Build and Test SwiftUI App (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build Unsigned iOS IPA (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build macOS ZIP (push) Canceled after 0s
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.
2026-08-18 22:58:18 +07:00

36 lines
1.1 KiB
Swift

import Foundation
#if os(iOS)
import UIKit
typealias ChatMediaPlatformImage = UIImage
#elseif os(macOS)
import AppKit
typealias ChatMediaPlatformImage = NSImage
#endif
/// SwiftUI can evaluate every visible bubble repeatedly during scrolling.
/// Keep decoded thumbnails in a bounded native-image cache so those passes do
/// not repeatedly decompress JPEG/HEIC data on the main actor.
@MainActor
enum ChatMediaImageCache {
private static let cache: NSCache<NSString, ChatMediaPlatformImage> = {
let cache = NSCache<NSString, ChatMediaPlatformImage>()
cache.countLimit = 160
cache.totalCostLimit = 48 * 1_024 * 1_024
return cache
}()
static func image(
for message: ChatMessage,
data: Data
) -> ChatMediaPlatformImage? {
let cacheKey = "\(message.conversationID)\u{1F}\(message.clientID)" as NSString
if let cached = cache.object(forKey: cacheKey) {
return cached
}
guard let image = ChatMediaPlatformImage(data: data) else { return nil }
cache.setObject(image, forKey: cacheKey, cost: data.count)
return image
}
}