From 152e88138be912fc5e5ab46f1778dccae63a0dc8 Mon Sep 17 00:00:00 2001 From: Laurent Date: Wed, 15 Feb 2023 16:33:47 +0100 Subject: [PATCH] Enables cloudkit --- LeCountdown/LeCountdown.entitlements | 10 ++++++ LeCountdown/Model/Persistence.swift | 17 ++++++++++ LeCountdown/Views/ContentView.swift | 51 ++++++++++++++++------------ LeCountdown/Views/PresetsView.swift | 3 ++ 4 files changed, 60 insertions(+), 21 deletions(-) diff --git a/LeCountdown/LeCountdown.entitlements b/LeCountdown/LeCountdown.entitlements index a7c6d47..7567a62 100644 --- a/LeCountdown/LeCountdown.entitlements +++ b/LeCountdown/LeCountdown.entitlements @@ -2,6 +2,16 @@ + aps-environment + development + com.apple.developer.icloud-container-identifiers + + iCloud.LeCountdown + + com.apple.developer.icloud-services + + CloudKit + com.apple.security.application-groups group.com.staxriver.countdown diff --git a/LeCountdown/Model/Persistence.swift b/LeCountdown/Model/Persistence.swift index 0bdef58..ac4cd85 100644 --- a/LeCountdown/Model/Persistence.swift +++ b/LeCountdown/Model/Persistence.swift @@ -48,14 +48,30 @@ struct PersistenceController { let storeURL = URL.storeURL(for: "group.com.staxriver.countdown", databaseName: "group.com.staxriver.countdown") let storeDescription = NSPersistentStoreDescription(url: storeURL) + // storeDescription.shouldMigrateStoreAutomatically = true // storeDescription.shouldInferMappingModelAutomatically = true + let id = "iCloud.LeCountdown" + let options = NSPersistentCloudKitContainerOptions(containerIdentifier: id) + storeDescription.cloudKitContainerOptions = options + + let remoteChangeKey = "NSPersistentStoreRemoteChangeNotificationOptionKey" + storeDescription.setOption(true as NSNumber, forKey: remoteChangeKey) + container = NSPersistentCloudKitContainer(name: "LeCountdown") container.persistentStoreDescriptions = [storeDescription] + if inMemory { container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") } + +// do { +// try container.initializeCloudKitSchema() +// } catch { +// fatalError("Unresolved error \(error)") +// } + container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { // Replace this implementation with code to handle the error appropriately. @@ -72,6 +88,7 @@ struct PersistenceController { fatalError("Unresolved error \(error), \(error.userInfo)") } }) + container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy container.viewContext.automaticallyMergesChangesFromParent = true } diff --git a/LeCountdown/Views/ContentView.swift b/LeCountdown/Views/ContentView.swift index e8bf6d2..c42c842 100644 --- a/LeCountdown/Views/ContentView.swift +++ b/LeCountdown/Views/ContentView.swift @@ -7,6 +7,8 @@ import SwiftUI import CoreData +import Combine +import CloudKit class BoringContext : ObservableObject { @@ -64,6 +66,11 @@ struct ContentView: View { } } + var coreDataPublisher: NotificationCenter.Publisher { NotificationCenter.default + .publisher(for: .NSManagedObjectContextDidSave, object: viewContext) } + var cloudkitPublisher: NotificationCenter.Publisher { NotificationCenter.default + .publisher(for: Notification.Name(rawValue: "NSPersistentStoreRemoteChangeNotificationOptionKey"), object: viewContext) } + @State private var isEditing: Bool = false { didSet { if self.isEditing == false { @@ -80,10 +87,6 @@ struct ContentView: View { GridItem(spacing: 10.0), ] - var timersArray: [T] { - return Array(timers) - } - var body: some View { GeometryReader { reader in @@ -158,11 +161,6 @@ struct ContentView: View { .sheet(isPresented: $boringContext.isShowingNewData, content: { self._newView(isPresented: $boringContext.isShowingNewData) .environment(\.managedObjectContext, viewContext) - .onDisappear { - withAnimation { - self._buildItemsList() - } - } }) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { @@ -184,6 +182,17 @@ struct ContentView: View { } } } +// .onReceive(cloudkitPublisher, perform: { _ in +// print(">>>cloudkitPublisher") +// withAnimation { +// self._buildItemsList() +// } +// }) + .onReceive(coreDataPublisher, perform: { _ in + withAnimation { + self._buildItemsList() + } + }) .onAppear { self._buildItemsList() self._askPermissions() @@ -246,18 +255,18 @@ struct ContentView: View { self.model.spots = spots } - fileprivate func _reorder(from: IndexSet, to: Int) { - var timers: [AbstractTimer] = self.timersArray - timers.move(fromOffsets: from, toOffset: to) - for (i, countdown) in timers.enumerated() { - countdown.order = Int16(i) - } - do { - try viewContext.save() - } catch { - self.boringContext.error = error - } - } +// fileprivate func _reorder(from: IndexSet, to: Int) { +// var timers: [AbstractTimer] = Array(self.timers) +// timers.move(fromOffsets: from, toOffset: to) +// for (i, countdown) in timers.enumerated() { +// countdown.order = Int16(i) +// } +// do { +// try viewContext.save() +// } catch { +// self.boringContext.error = error +// } +// } fileprivate func _askPermissions() { UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .criticalAlert]) { success, error in diff --git a/LeCountdown/Views/PresetsView.swift b/LeCountdown/Views/PresetsView.swift index d2ae2aa..33a9ee4 100644 --- a/LeCountdown/Views/PresetsView.swift +++ b/LeCountdown/Views/PresetsView.swift @@ -13,11 +13,13 @@ enum PresetSection: Int, Identifiable, CaseIterable { case workout case chill case cooking + case tea case other var presets: [Preset] { switch self { case .cooking: return [.softBoiled, .mediumBoiledEggs, .hardBoiledEggs] + case .tea: return [.greenTea, .blackTea] case .workout: return [.runningSplits] case .chill: return [.nap, .meditation] case .other: return [.toothbrushing] @@ -30,6 +32,7 @@ enum PresetSection: Int, Identifiable, CaseIterable { case .workout: return NSLocalizedString("Workout", comment: "") case .chill: return NSLocalizedString("Chill", comment: "") case .other: return NSLocalizedString("Other", comment: "") + case .tea: return NSLocalizedString("Tea", comment: "") } } }