mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2024-12-22 23:58:36 +01:00
Move CloudKitAccountZone to CloudKitSync module.
This commit is contained in:
parent
b64b1307b7
commit
fe017d042a
@ -36,31 +36,31 @@ public typealias CloudKitRecordKey = (recordType: CKRecord.RecordType, recordID:
|
||||
|
||||
public protocol CloudKitZone: AnyObject {
|
||||
|
||||
static var qualityOfService: QualityOfService { get }
|
||||
@MainActor static var qualityOfService: QualityOfService { get }
|
||||
|
||||
var zoneID: CKRecordZone.ID { get }
|
||||
|
||||
var log: OSLog { get }
|
||||
@MainActor var log: OSLog { get }
|
||||
|
||||
@MainActor var container: CKContainer? { get }
|
||||
@MainActor var database: CKDatabase? { get }
|
||||
@MainActor var delegate: CloudKitZoneDelegate? { get set }
|
||||
|
||||
/// Reset the change token used to determine what point in time we are doing changes fetches
|
||||
func resetChangeToken()
|
||||
@MainActor func resetChangeToken()
|
||||
|
||||
/// Generates a new CKRecord.ID using a UUID for the record's name
|
||||
func generateRecordID() -> CKRecord.ID
|
||||
|
||||
@MainActor func generateRecordID() -> CKRecord.ID
|
||||
|
||||
/// Subscribe to changes at a zone level
|
||||
func subscribeToZoneChanges()
|
||||
@MainActor func subscribeToZoneChanges()
|
||||
|
||||
/// Process a remove notification
|
||||
func receiveRemoteNotification(userInfo: [AnyHashable : Any]) async
|
||||
@MainActor func receiveRemoteNotification(userInfo: [AnyHashable : Any]) async
|
||||
}
|
||||
|
||||
@MainActor public extension CloudKitZone {
|
||||
|
||||
|
||||
// My observation has been that QoS is treated differently for CloudKit operations on macOS vs iOS.
|
||||
// .userInitiated is too aggressive on iOS and can lead the UI slowing down and appearing to block.
|
||||
// .default (or lower) on macOS will sometimes hang for extended periods of time and appear to hang.
|
||||
@ -71,7 +71,7 @@ public protocol CloudKitZone: AnyObject {
|
||||
return .default
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
var oldChangeTokenKey: String {
|
||||
return "cloudkit.server.token.\(zoneID.zoneName)"
|
||||
}
|
||||
@ -130,29 +130,17 @@ public protocol CloudKitZone: AnyObject {
|
||||
})
|
||||
}
|
||||
|
||||
func receiveRemoteNotification(userInfo: [AnyHashable : Any]) async {
|
||||
@MainActor func receiveRemoteNotification(userInfo: [AnyHashable : Any]) async {
|
||||
|
||||
await withCheckedContinuation { continuation in
|
||||
Task { @MainActor in
|
||||
self.receiveRemoteNotification(userInfo: userInfo) {
|
||||
continuation.resume()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor func receiveRemoteNotification(userInfo: [AnyHashable : Any], completion: @escaping @Sendable () -> Void) {
|
||||
let note = CKRecordZoneNotification(fromRemoteNotificationDictionary: userInfo)
|
||||
guard note?.recordZoneID?.zoneName == zoneID.zoneName else {
|
||||
completion()
|
||||
return
|
||||
}
|
||||
|
||||
fetchChangesInZone() { result in
|
||||
if case .failure(let error) = result {
|
||||
os_log(.error, log: self.log, "%@ zone remote notification fetch error: %@", self.zoneID.zoneName, error.localizedDescription)
|
||||
}
|
||||
completion()
|
||||
do {
|
||||
try await fetchChangesInZone()
|
||||
} catch {
|
||||
os_log(.error, log: log, "%@ zone remote notification fetch error: %@", zoneID.zoneName, error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,18 @@
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "CloudKitSyncTests"
|
||||
BuildableName = "CloudKitSyncTests"
|
||||
BlueprintName = "CloudKitSyncTests"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
|
@ -94,7 +94,7 @@ enum CloudKitAccountZoneError: LocalizedError {
|
||||
}
|
||||
|
||||
/// Persist a web feed record to iCloud and return the external key
|
||||
func createFeed(url: String, name: String?, editedName: String?, homePageURL: String?, container: Container) async throws -> String {
|
||||
func createFeed(url: String, name: String?, editedName: String?, homePageURL: String?, containerExternalID: String) async throws -> String {
|
||||
|
||||
let recordID = CKRecord.ID(recordName: url.md5String, zoneID: zoneID)
|
||||
let record = CKRecord(recordType: CloudKitFeed.recordType, recordID: recordID)
|
||||
@ -107,9 +107,6 @@ enum CloudKitAccountZoneError: LocalizedError {
|
||||
record[CloudKitFeed.Fields.homePageURL] = homePageURL
|
||||
}
|
||||
|
||||
guard let containerExternalID = container.externalID else {
|
||||
throw CloudKitZoneError.corruptAccount
|
||||
}
|
||||
record[CloudKitFeed.Fields.containerExternalIDs] = [containerExternalID]
|
||||
|
||||
try await save(record)
|
||||
@ -117,11 +114,7 @@ enum CloudKitAccountZoneError: LocalizedError {
|
||||
}
|
||||
|
||||
/// Rename the given web feed
|
||||
func renameFeed(_ feed: Feed, editedName: String?) async throws {
|
||||
|
||||
guard let externalID = feed.externalID else {
|
||||
throw CloudKitZoneError.corruptAccount
|
||||
}
|
||||
func renameFeed(externalID: String, editedName: String?) async throws {
|
||||
|
||||
let recordID = CKRecord.ID(recordName: externalID, zoneID: zoneID)
|
||||
let record = CKRecord(recordType: CloudKitFeed.recordType, recordID: recordID)
|
||||
@ -132,22 +125,18 @@ enum CloudKitAccountZoneError: LocalizedError {
|
||||
|
||||
/// Removes a web feed from a container and optionally deletes it, returning true if deleted
|
||||
@discardableResult
|
||||
func removeFeed(_ feed: Feed, from: Container) async throws -> Bool {
|
||||
|
||||
guard let fromContainerExternalID = from.externalID else {
|
||||
throw CloudKitZoneError.corruptAccount
|
||||
}
|
||||
func removeFeed(externalID: String, from containerExternalID: String) async throws -> Bool {
|
||||
|
||||
do {
|
||||
let record = try await fetch(externalID: feed.externalID)
|
||||
let record = try await fetch(externalID: externalID)
|
||||
|
||||
if let containerExternalIDs = record[CloudKitFeed.Fields.containerExternalIDs] as? [String] {
|
||||
|
||||
var containerExternalIDSet = Set(containerExternalIDs)
|
||||
containerExternalIDSet.remove(fromContainerExternalID)
|
||||
containerExternalIDSet.remove(containerExternalID)
|
||||
|
||||
if containerExternalIDSet.isEmpty {
|
||||
try await delete(externalID: feed.externalID)
|
||||
try await delete(externalID: externalID)
|
||||
return true
|
||||
} else {
|
||||
record[CloudKitFeed.Fields.containerExternalIDs] = Array(containerExternalIDSet)
|
||||
@ -166,44 +155,32 @@ enum CloudKitAccountZoneError: LocalizedError {
|
||||
}
|
||||
}
|
||||
|
||||
func moveFeed(_ feed: Feed, from: Container, to: Container) async throws {
|
||||
func moveFeed(externalID: String, from sourceContainerExternalID: String, to destinationContainerExternalID: String) async throws {
|
||||
|
||||
guard let fromContainerExternalID = from.externalID, let toContainerExternalID = to.externalID else {
|
||||
throw CloudKitZoneError.corruptAccount
|
||||
}
|
||||
|
||||
let record = try await fetch(externalID: feed.externalID)
|
||||
let record = try await fetch(externalID: externalID)
|
||||
|
||||
if let containerExternalIDs = record[CloudKitFeed.Fields.containerExternalIDs] as? [String] {
|
||||
var containerExternalIDSet = Set(containerExternalIDs)
|
||||
containerExternalIDSet.remove(fromContainerExternalID)
|
||||
containerExternalIDSet.insert(toContainerExternalID)
|
||||
containerExternalIDSet.remove(sourceContainerExternalID)
|
||||
containerExternalIDSet.insert(destinationContainerExternalID)
|
||||
record[CloudKitFeed.Fields.containerExternalIDs] = Array(containerExternalIDSet)
|
||||
try await save(record)
|
||||
}
|
||||
}
|
||||
|
||||
func addFeed(_ feed: Feed, to: Container) async throws {
|
||||
func addFeed(externalID: String, to containerExternalID: String) async throws {
|
||||
|
||||
guard let toContainerExternalID = to.externalID else {
|
||||
throw CloudKitZoneError.corruptAccount
|
||||
}
|
||||
|
||||
let record = try await fetch(externalID: feed.externalID)
|
||||
let record = try await fetch(externalID: externalID)
|
||||
|
||||
if let containerExternalIDs = record[CloudKitFeed.Fields.containerExternalIDs] as? [String] {
|
||||
var containerExternalIDSet = Set(containerExternalIDs)
|
||||
containerExternalIDSet.insert(toContainerExternalID)
|
||||
containerExternalIDSet.insert(containerExternalID)
|
||||
record[CloudKitFeed.Fields.containerExternalIDs] = Array(containerExternalIDSet)
|
||||
try await save(record)
|
||||
}
|
||||
}
|
||||
|
||||
func findFeedExternalIDs(for folder: Folder) async throws -> [String] {
|
||||
|
||||
guard let folderExternalID = folder.externalID else {
|
||||
throw CloudKitAccountZoneError.unknown
|
||||
}
|
||||
func findFeedExternalIDs(for folderExternalID: String) async throws -> [String] {
|
||||
|
||||
let predicate = NSPredicate(format: "containerExternalIDs CONTAINS %@", folderExternalID)
|
||||
let ckQuery = CKQuery(recordType: CloudKitFeed.recordType, predicate: predicate)
|
||||
@ -216,9 +193,7 @@ enum CloudKitAccountZoneError: LocalizedError {
|
||||
|
||||
func findOrCreateAccount() async throws -> String {
|
||||
|
||||
guard let database else {
|
||||
throw CloudKitAccountZoneError.unknown
|
||||
}
|
||||
guard let database else { throw CloudKitAccountZoneError.unknown }
|
||||
|
||||
let predicate = NSPredicate(format: "isAccount = \"1\"")
|
||||
let ckQuery = CKQuery(recordType: CloudKitContainer.recordType, predicate: predicate)
|
||||
@ -254,11 +229,7 @@ enum CloudKitAccountZoneError: LocalizedError {
|
||||
return try await createContainer(name: name, isAccount: false)
|
||||
}
|
||||
|
||||
func renameFolder(_ folder: Folder, to name: String) async throws {
|
||||
|
||||
guard let externalID = folder.externalID else {
|
||||
throw CloudKitZoneError.corruptAccount
|
||||
}
|
||||
func renameFolder(externalID: String, to name: String) async throws {
|
||||
|
||||
let recordID = CKRecord.ID(recordName: externalID, zoneID: zoneID)
|
||||
let record = CKRecord(recordType: CloudKitContainer.recordType, recordID: recordID)
|
||||
@ -267,9 +238,9 @@ enum CloudKitAccountZoneError: LocalizedError {
|
||||
try await save(record)
|
||||
}
|
||||
|
||||
func removeFolder(_ folder: Folder) async throws {
|
||||
func removeFolder(externalID: String) async throws {
|
||||
|
||||
try await delete(externalID: folder.externalID)
|
||||
try await delete(externalID: externalID)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user