Compare commits
3 Commits
fc391cc18c
...
6261318df1
Author | SHA1 | Date |
---|---|---|
Shadowfacts | 6261318df1 | |
Shadowfacts | bff7585fa9 | |
Shadowfacts | 4dbc4ebeb2 |
|
@ -1,5 +1,8 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2023.5 (89)
|
||||||
|
This build is a hotfix for an issue loading notifications in certain circumstances. The changelong for the previous build (adding post editing) is included below.
|
||||||
|
|
||||||
## 2023.5 (85)
|
## 2023.5 (85)
|
||||||
This build adds support for editing posts and showing edit timestamps and history.
|
This build adds support for editing posts and showing edit timestamps and history.
|
||||||
|
|
||||||
|
|
|
@ -2370,7 +2370,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 85;
|
CURRENT_PROJECT_VERSION = 89;
|
||||||
INFOPLIST_FILE = Tusker/Info.plist;
|
INFOPLIST_FILE = Tusker/Info.plist;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
@ -2436,7 +2436,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 85;
|
CURRENT_PROJECT_VERSION = 89;
|
||||||
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.3;
|
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.3;
|
||||||
|
@ -2462,7 +2462,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 85;
|
CURRENT_PROJECT_VERSION = 89;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = ShareExtension/Info.plist;
|
INFOPLIST_FILE = ShareExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
||||||
|
@ -2491,7 +2491,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 85;
|
CURRENT_PROJECT_VERSION = 89;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = ShareExtension/Info.plist;
|
INFOPLIST_FILE = ShareExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
||||||
|
@ -2520,7 +2520,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 85;
|
CURRENT_PROJECT_VERSION = 89;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = ShareExtension/Info.plist;
|
INFOPLIST_FILE = ShareExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
||||||
|
@ -2675,7 +2675,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 85;
|
CURRENT_PROJECT_VERSION = 89;
|
||||||
INFOPLIST_FILE = Tusker/Info.plist;
|
INFOPLIST_FILE = Tusker/Info.plist;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
@ -2706,7 +2706,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 85;
|
CURRENT_PROJECT_VERSION = 89;
|
||||||
INFOPLIST_FILE = Tusker/Info.plist;
|
INFOPLIST_FILE = Tusker/Info.plist;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
@ -2812,7 +2812,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 85;
|
CURRENT_PROJECT_VERSION = 89;
|
||||||
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.3;
|
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.3;
|
||||||
|
@ -2838,7 +2838,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 85;
|
CURRENT_PROJECT_VERSION = 89;
|
||||||
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.3;
|
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.3;
|
||||||
|
|
|
@ -31,18 +31,21 @@ class MastodonCachePersistentStore: NSPersistentCloudKitContainer {
|
||||||
context.persistentStoreCoordinator = self.persistentStoreCoordinator
|
context.persistentStoreCoordinator = self.persistentStoreCoordinator
|
||||||
context.automaticallyMergesChangesFromParent = true
|
context.automaticallyMergesChangesFromParent = true
|
||||||
context.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
|
context.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
|
||||||
|
context.name = "Background"
|
||||||
return context
|
return context
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private(set) lazy var prefetchBackgroundContext: NSManagedObjectContext = {
|
// remote change processing happens on its own context, since it can sometimes take
|
||||||
|
// a really long time (upwards of a minute) and shouldn't block other things using the background context
|
||||||
|
private lazy var remoteChangesBackgroundContext: NSManagedObjectContext = {
|
||||||
let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
|
let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
|
||||||
context.persistentStoreCoordinator = self.persistentStoreCoordinator
|
context.persistentStoreCoordinator = self.persistentStoreCoordinator
|
||||||
context.automaticallyMergesChangesFromParent = true
|
context.automaticallyMergesChangesFromParent = true
|
||||||
context.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
|
context.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
|
||||||
|
context.name = "RemoteChanges"
|
||||||
return context
|
return context
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private var remoteChangeHandlerQueue = DispatchQueue(label: "PersistentStore remote changes")
|
|
||||||
private var lastRemoteChangeToken: NSPersistentHistoryToken?
|
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
|
||||||
|
@ -182,6 +185,7 @@ class MastodonCachePersistentStore: NSPersistentCloudKitContainer {
|
||||||
|
|
||||||
viewContext.automaticallyMergesChangesFromParent = true
|
viewContext.automaticallyMergesChangesFromParent = true
|
||||||
viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
|
viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
|
||||||
|
viewContext.name = "View"
|
||||||
|
|
||||||
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)
|
NotificationCenter.default.addObserver(self, selector: #selector(remoteChanges), name: .NSPersistentStoreRemoteChange, object: persistentStoreCoordinator)
|
||||||
|
@ -509,50 +513,48 @@ class MastodonCachePersistentStore: NSPersistentCloudKitContainer {
|
||||||
guard let token = notification.userInfo?[NSPersistentHistoryTokenKey] as? NSPersistentHistoryToken else {
|
guard let token = notification.userInfo?[NSPersistentHistoryTokenKey] as? NSPersistentHistoryToken else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
remoteChangeHandlerQueue.async {
|
remoteChangesBackgroundContext.perform {
|
||||||
defer {
|
defer {
|
||||||
self.lastRemoteChangeToken = token
|
self.lastRemoteChangeToken = token
|
||||||
}
|
}
|
||||||
let req = NSPersistentHistoryChangeRequest.fetchHistory(after: self.lastRemoteChangeToken)
|
let req = NSPersistentHistoryChangeRequest.fetchHistory(after: self.lastRemoteChangeToken)
|
||||||
self.backgroundContext.performAndWait {
|
if let result = try? self.remoteChangesBackgroundContext.execute(req) as? NSPersistentHistoryResult,
|
||||||
if let result = try? self.backgroundContext.execute(req) as? NSPersistentHistoryResult,
|
let transactions = result.result as? [NSPersistentHistoryTransaction],
|
||||||
let transactions = result.result as? [NSPersistentHistoryTransaction],
|
!transactions.isEmpty {
|
||||||
!transactions.isEmpty {
|
var changedHashtags = false
|
||||||
var changedHashtags = false
|
var changedInstances = false
|
||||||
var changedInstances = false
|
var changedTimelinePositions = Set<NSManagedObjectID>()
|
||||||
var changedTimelinePositions = Set<NSManagedObjectID>()
|
var changedAccountPrefs = false
|
||||||
var changedAccountPrefs = false
|
outer: for transaction in transactions {
|
||||||
outer: for transaction in transactions {
|
for change in transaction.changes ?? [] {
|
||||||
for change in transaction.changes ?? [] {
|
if change.changedObjectID.entity.name == "SavedHashtag" {
|
||||||
if change.changedObjectID.entity.name == "SavedHashtag" {
|
changedHashtags = true
|
||||||
changedHashtags = true
|
} else if change.changedObjectID.entity.name == "SavedInstance" {
|
||||||
} else if change.changedObjectID.entity.name == "SavedInstance" {
|
changedInstances = true
|
||||||
changedInstances = true
|
} else if change.changedObjectID.entity.name == "TimelinePosition" {
|
||||||
} else if change.changedObjectID.entity.name == "TimelinePosition" {
|
changedTimelinePositions.insert(change.changedObjectID)
|
||||||
changedTimelinePositions.insert(change.changedObjectID)
|
} else if change.changedObjectID.entity.name == "AccountPreferences" {
|
||||||
} else if change.changedObjectID.entity.name == "AccountPreferences" {
|
changedAccountPrefs = true
|
||||||
changedAccountPrefs = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DispatchQueue.main.async {
|
}
|
||||||
if changedHashtags {
|
DispatchQueue.main.async {
|
||||||
NotificationCenter.default.post(name: .savedHashtagsChanged, object: nil)
|
if changedHashtags {
|
||||||
}
|
NotificationCenter.default.post(name: .savedHashtagsChanged, object: nil)
|
||||||
if changedInstances {
|
}
|
||||||
NotificationCenter.default.post(name: .savedInstancesChanged, object: nil)
|
if changedInstances {
|
||||||
}
|
NotificationCenter.default.post(name: .savedInstancesChanged, object: nil)
|
||||||
for id in changedTimelinePositions {
|
}
|
||||||
guard let timelinePosition = try? self.viewContext.existingObject(with: id) as? TimelinePosition else {
|
for id in changedTimelinePositions {
|
||||||
continue
|
guard let timelinePosition = try? self.viewContext.existingObject(with: id) as? TimelinePosition else {
|
||||||
}
|
continue
|
||||||
// the kvo observer that clears the LazilyDecoding cache doesn't always fire on remote changes, so do it manually
|
|
||||||
timelinePosition.changedRemotely()
|
|
||||||
NotificationCenter.default.post(name: .timelinePositionChanged, object: timelinePosition)
|
|
||||||
}
|
|
||||||
if changedAccountPrefs {
|
|
||||||
NotificationCenter.default.post(name: .accountPreferencesChangedRemotely, object: nil)
|
|
||||||
}
|
}
|
||||||
|
// the kvo observer that clears the LazilyDecoding cache doesn't always fire on remote changes, so do it manually
|
||||||
|
timelinePosition.changedRemotely()
|
||||||
|
NotificationCenter.default.post(name: .timelinePositionChanged, object: timelinePosition)
|
||||||
|
}
|
||||||
|
if changedAccountPrefs {
|
||||||
|
NotificationCenter.default.post(name: .accountPreferencesChangedRemotely, object: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,13 @@ struct Logging {
|
||||||
let entries = try store.getEntries()
|
let entries = try store.getEntries()
|
||||||
var data = Data()
|
var data = Data()
|
||||||
let subsystem = Bundle.main.bundleIdentifier!
|
let subsystem = Bundle.main.bundleIdentifier!
|
||||||
|
let format = Date.ISO8601FormatStyle(includingFractionalSeconds: true)
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
guard let entry = entry as? OSLogEntryLog,
|
guard let entry = entry as? OSLogEntryLog,
|
||||||
entry.subsystem == subsystem else {
|
entry.subsystem == subsystem else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
data.append(contentsOf: entry.date.formatted(.iso8601).utf8)
|
data.append(contentsOf: entry.date.formatted(format).utf8)
|
||||||
data.append(32) // ' '
|
data.append(32) // ' '
|
||||||
data.append(91) // '['
|
data.append(91) // '['
|
||||||
data.append(contentsOf: entry.category.utf8)
|
data.append(contentsOf: entry.category.utf8)
|
||||||
|
|
Loading…
Reference in New Issue