forked from shadowfacts/Tusker
127 lines
4.6 KiB
Swift
127 lines
4.6 KiB
Swift
//
|
|
// DraftsPersistentContainer.swift
|
|
// ComposeUI
|
|
//
|
|
// Created by Shadowfacts on 4/22/23.
|
|
//
|
|
|
|
import Foundation
|
|
import CoreData
|
|
import OSLog
|
|
import Pachyderm
|
|
|
|
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "DraftsPersistentContainer")
|
|
|
|
public class DraftsPersistentContainer: NSPersistentContainer {
|
|
|
|
public static let shared = DraftsPersistentContainer()
|
|
|
|
private static let managedObjectModel: NSManagedObjectModel = {
|
|
let url = Bundle.module.url(forResource: "Drafts", withExtension: "momd")!
|
|
return NSManagedObjectModel(contentsOf: url)!
|
|
}()
|
|
|
|
private var lastHistoryToken: NSPersistentHistoryToken!
|
|
|
|
init() {
|
|
super.init(name: "Drafts", managedObjectModel: DraftsPersistentContainer.managedObjectModel)
|
|
|
|
let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.space.vaccor.Tusker")!
|
|
let documentsURL = containerURL.appendingPathComponent("Documents")
|
|
let storeDesc = NSPersistentStoreDescription(url: documentsURL.appendingPathComponent("drafts").appendingPathExtension("sqlite"))
|
|
storeDesc.type = NSSQLiteStoreType
|
|
storeDesc.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
|
|
storeDesc.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
|
|
|
|
persistentStoreDescriptions = [
|
|
storeDesc
|
|
]
|
|
|
|
loadPersistentStores { _, error in
|
|
if let error {
|
|
fatalError("Loading persistent store: \(error)")
|
|
}
|
|
}
|
|
|
|
viewContext.automaticallyMergesChangesFromParent = true
|
|
viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
|
|
|
|
lastHistoryToken = persistentStoreCoordinator.currentPersistentHistoryToken(fromStores: nil)
|
|
|
|
NotificationCenter.default.addObserver(self, selector: #selector(remoteChanges(_:)), name: .NSPersistentStoreRemoteChange, object: persistentStoreCoordinator)
|
|
}
|
|
|
|
public func save() {
|
|
guard viewContext.hasChanges else {
|
|
return
|
|
}
|
|
do {
|
|
try viewContext.save()
|
|
} catch {
|
|
logger.error("Failed to save: \(String(describing: error))")
|
|
}
|
|
}
|
|
|
|
public func migrate(from url: URL, completion: @escaping (Result<(), any Error>) -> Void) {
|
|
performBackgroundTask { context in
|
|
let result = DraftsMigrator.migrate(from: url, to: context)
|
|
completion(result)
|
|
try! context.save()
|
|
}
|
|
}
|
|
|
|
public func getDraft(id: UUID) -> Draft? {
|
|
let req = Draft.fetchRequest(id: id)
|
|
return try? viewContext.fetch(req).first
|
|
}
|
|
|
|
public func createDraft(
|
|
accountID: String,
|
|
text: String,
|
|
contentWarning: String,
|
|
inReplyToID: String?,
|
|
visibility: Visibility,
|
|
localOnly: Bool
|
|
) -> Draft {
|
|
let draft = Draft(context: viewContext)
|
|
draft.accountID = accountID
|
|
draft.text = text
|
|
draft.initialText = text
|
|
draft.contentWarning = contentWarning
|
|
draft.contentWarningEnabled = !contentWarning.isEmpty
|
|
draft.inReplyToID = inReplyToID
|
|
draft.visibility = visibility
|
|
draft.localOnly = localOnly
|
|
save()
|
|
return draft
|
|
}
|
|
|
|
@objc private func remoteChanges(_ notification: Foundation.Notification) {
|
|
guard let newHistoryToken = notification.userInfo?[NSPersistentHistoryTokenKey] as? NSPersistentHistoryToken else {
|
|
return
|
|
}
|
|
|
|
// todo: should this be on a background context?
|
|
let context = viewContext
|
|
context.perform {
|
|
let predicate = NSPredicate(format: "(%@ < token) AND (token <= %@)", self.lastHistoryToken, newHistoryToken)
|
|
|
|
let historyRequest = NSPersistentHistoryTransaction.fetchRequest!
|
|
historyRequest.predicate = predicate
|
|
let request = NSPersistentHistoryChangeRequest.fetchHistory(withFetch: historyRequest)
|
|
if let result = try? context.execute(request) as? NSPersistentHistoryResult,
|
|
let transactions = result.result as? [NSPersistentHistoryTransaction] {
|
|
for transaction in transactions {
|
|
guard let userInfo = transaction.objectIDNotification().userInfo else {
|
|
continue
|
|
}
|
|
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: userInfo, into: [context])
|
|
}
|
|
}
|
|
|
|
self.lastHistoryToken = newHistoryToken
|
|
}
|
|
}
|
|
|
|
}
|