forked from shadowfacts/Tusker
Update UI in responds to remote changes of saved hashtags/instances
This commit is contained in:
parent
d13b517128
commit
32be76ebee
|
@ -39,6 +39,9 @@ class MastodonCachePersistentStore: NSPersistentCloudKitContainer {
|
||||||
return context
|
return context
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
private var remoteChangeHandlerQueue = DispatchQueue(label: "PersistentStore remote changes")
|
||||||
|
private var lastRemoteChangeToken: NSPersistentHistoryToken?
|
||||||
|
|
||||||
// TODO: consider sending managed objects through this to avoid re-fetching things unnecessarily
|
// TODO: consider sending managed objects through this to avoid re-fetching things unnecessarily
|
||||||
// would need to audit existing uses to make sure everything happens on the main thread
|
// would need to audit existing uses to make sure everything happens on the main thread
|
||||||
// and when updating things on the background context would need to switch to main, refetch, and then publish
|
// and when updating things on the background context would need to switch to main, refetch, and then publish
|
||||||
|
@ -63,6 +66,8 @@ class MastodonCachePersistentStore: NSPersistentCloudKitContainer {
|
||||||
localStoreLocation.appendPathComponent("\(accountInfo!.persistenceKey)_cache.sqlite", isDirectory: false)
|
localStoreLocation.appendPathComponent("\(accountInfo!.persistenceKey)_cache.sqlite", isDirectory: false)
|
||||||
let localStoreDescription = NSPersistentStoreDescription(url: localStoreLocation)
|
let localStoreDescription = NSPersistentStoreDescription(url: localStoreLocation)
|
||||||
localStoreDescription.configuration = "Local"
|
localStoreDescription.configuration = "Local"
|
||||||
|
localStoreDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
|
||||||
|
localStoreDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
|
||||||
|
|
||||||
var cloudStoreLocation = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
|
var cloudStoreLocation = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
|
||||||
cloudStoreLocation.appendPathComponent("cloud.sqlite", isDirectory: false)
|
cloudStoreLocation.appendPathComponent("cloud.sqlite", isDirectory: false)
|
||||||
|
@ -71,6 +76,8 @@ class MastodonCachePersistentStore: NSPersistentCloudKitContainer {
|
||||||
let options = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.space.vaccor.Tusker")
|
let options = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.space.vaccor.Tusker")
|
||||||
options.databaseScope = .private
|
options.databaseScope = .private
|
||||||
cloudStoreDescription.cloudKitContainerOptions = options
|
cloudStoreDescription.cloudKitContainerOptions = options
|
||||||
|
cloudStoreDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
|
||||||
|
cloudStoreDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
|
||||||
|
|
||||||
persistentStoreDescriptions = [
|
persistentStoreDescriptions = [
|
||||||
cloudStoreDescription,
|
cloudStoreDescription,
|
||||||
|
@ -167,6 +174,7 @@ class MastodonCachePersistentStore: NSPersistentCloudKitContainer {
|
||||||
viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
|
viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(managedObjectsDidChange), name: .NSManagedObjectContextObjectsDidChange, object: viewContext)
|
NotificationCenter.default.addObserver(self, selector: #selector(managedObjectsDidChange), name: .NSManagedObjectContextObjectsDidChange, object: viewContext)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(remoteChanges), name: .NSPersistentStoreRemoteChange, object: persistentStoreCoordinator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func save(context: NSManagedObjectContext) {
|
func save(context: NSManagedObjectContext) {
|
||||||
|
@ -475,4 +483,45 @@ class MastodonCachePersistentStore: NSPersistentCloudKitContainer {
|
||||||
return changes
|
return changes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the remote change notifications only handle deletes, inserts get handled by the regular managed object did change notifications
|
||||||
|
@objc private func remoteChanges(_ notification: Foundation.Notification) {
|
||||||
|
guard let token = notification.userInfo?[NSPersistentHistoryTokenKey] as? NSPersistentHistoryToken else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
remoteChangeHandlerQueue.async {
|
||||||
|
defer {
|
||||||
|
self.lastRemoteChangeToken = token
|
||||||
|
}
|
||||||
|
let req = NSPersistentHistoryChangeRequest.fetchHistory(after: self.lastRemoteChangeToken)
|
||||||
|
self.backgroundContext.performAndWait {
|
||||||
|
if let result = try? self.backgroundContext.execute(req) as? NSPersistentHistoryResult,
|
||||||
|
let transactions = result.result as? [NSPersistentHistoryTransaction] {
|
||||||
|
var changes: (hashtags: Bool, instances: Bool) = (false, false)
|
||||||
|
outer: for transaction in transactions {
|
||||||
|
for change in transaction.changes ?? [] {
|
||||||
|
if change.changedObjectID.entity.name == "SavedHashtag" {
|
||||||
|
changes.hashtags = true
|
||||||
|
} else if change.changedObjectID.entity.name == "SavedInstance" {
|
||||||
|
changes.instances = true
|
||||||
|
}
|
||||||
|
if changes.hashtags && changes.instances {
|
||||||
|
break outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if changes.hashtags {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
NotificationCenter.default.post(name: .savedHashtagsChanged, object: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if changes.instances {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
NotificationCenter.default.post(name: .savedInstancesChanged, object: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue