Enables cloudkit

release
Laurent 3 years ago
parent 8b9016ddba
commit 152e88138b
  1. 10
      LeCountdown/LeCountdown.entitlements
  2. 17
      LeCountdown/Model/Persistence.swift
  3. 51
      LeCountdown/Views/ContentView.swift
  4. 3
      LeCountdown/Views/PresetsView.swift

@ -2,6 +2,16 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
<string>iCloud.LeCountdown</string>
</array>
<key>com.apple.developer.icloud-services</key>
<array>
<string>CloudKit</string>
</array>
<key>com.apple.security.application-groups</key> <key>com.apple.security.application-groups</key>
<array> <array>
<string>group.com.staxriver.countdown</string> <string>group.com.staxriver.countdown</string>

@ -48,14 +48,30 @@ struct PersistenceController {
let storeURL = URL.storeURL(for: "group.com.staxriver.countdown", databaseName: "group.com.staxriver.countdown") let storeURL = URL.storeURL(for: "group.com.staxriver.countdown", databaseName: "group.com.staxriver.countdown")
let storeDescription = NSPersistentStoreDescription(url: storeURL) let storeDescription = NSPersistentStoreDescription(url: storeURL)
// storeDescription.shouldMigrateStoreAutomatically = true // storeDescription.shouldMigrateStoreAutomatically = true
// storeDescription.shouldInferMappingModelAutomatically = 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 = NSPersistentCloudKitContainer(name: "LeCountdown")
container.persistentStoreDescriptions = [storeDescription] container.persistentStoreDescriptions = [storeDescription]
if inMemory { if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
} }
// do {
// try container.initializeCloudKitSchema()
// } catch {
// fatalError("Unresolved error \(error)")
// }
container.loadPersistentStores(completionHandler: { (storeDescription, error) in container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? { if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately. // Replace this implementation with code to handle the error appropriately.
@ -72,6 +88,7 @@ struct PersistenceController {
fatalError("Unresolved error \(error), \(error.userInfo)") fatalError("Unresolved error \(error), \(error.userInfo)")
} }
}) })
container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
container.viewContext.automaticallyMergesChangesFromParent = true container.viewContext.automaticallyMergesChangesFromParent = true
} }

@ -7,6 +7,8 @@
import SwiftUI import SwiftUI
import CoreData import CoreData
import Combine
import CloudKit
class BoringContext : ObservableObject { class BoringContext : ObservableObject {
@ -64,6 +66,11 @@ struct ContentView<T : AbstractTimer>: 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 { @State private var isEditing: Bool = false {
didSet { didSet {
if self.isEditing == false { if self.isEditing == false {
@ -80,10 +87,6 @@ struct ContentView<T : AbstractTimer>: View {
GridItem(spacing: 10.0), GridItem(spacing: 10.0),
] ]
var timersArray: [T] {
return Array(timers)
}
var body: some View { var body: some View {
GeometryReader { reader in GeometryReader { reader in
@ -158,11 +161,6 @@ struct ContentView<T : AbstractTimer>: View {
.sheet(isPresented: $boringContext.isShowingNewData, content: { .sheet(isPresented: $boringContext.isShowingNewData, content: {
self._newView(isPresented: $boringContext.isShowingNewData) self._newView(isPresented: $boringContext.isShowingNewData)
.environment(\.managedObjectContext, viewContext) .environment(\.managedObjectContext, viewContext)
.onDisappear {
withAnimation {
self._buildItemsList()
}
}
}) })
.toolbar { .toolbar {
ToolbarItem(placement: .navigationBarTrailing) { ToolbarItem(placement: .navigationBarTrailing) {
@ -184,6 +182,17 @@ struct ContentView<T : AbstractTimer>: View {
} }
} }
} }
// .onReceive(cloudkitPublisher, perform: { _ in
// print(">>>cloudkitPublisher")
// withAnimation {
// self._buildItemsList()
// }
// })
.onReceive(coreDataPublisher, perform: { _ in
withAnimation {
self._buildItemsList()
}
})
.onAppear { .onAppear {
self._buildItemsList() self._buildItemsList()
self._askPermissions() self._askPermissions()
@ -246,18 +255,18 @@ struct ContentView<T : AbstractTimer>: View {
self.model.spots = spots self.model.spots = spots
} }
fileprivate func _reorder(from: IndexSet, to: Int) { // fileprivate func _reorder(from: IndexSet, to: Int) {
var timers: [AbstractTimer] = self.timersArray // var timers: [AbstractTimer] = Array(self.timers)
timers.move(fromOffsets: from, toOffset: to) // timers.move(fromOffsets: from, toOffset: to)
for (i, countdown) in timers.enumerated() { // for (i, countdown) in timers.enumerated() {
countdown.order = Int16(i) // countdown.order = Int16(i)
} // }
do { // do {
try viewContext.save() // try viewContext.save()
} catch { // } catch {
self.boringContext.error = error // self.boringContext.error = error
} // }
} // }
fileprivate func _askPermissions() { fileprivate func _askPermissions() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .criticalAlert]) { success, error in UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .criticalAlert]) { success, error in

@ -13,11 +13,13 @@ enum PresetSection: Int, Identifiable, CaseIterable {
case workout case workout
case chill case chill
case cooking case cooking
case tea
case other case other
var presets: [Preset] { var presets: [Preset] {
switch self { switch self {
case .cooking: return [.softBoiled, .mediumBoiledEggs, .hardBoiledEggs] case .cooking: return [.softBoiled, .mediumBoiledEggs, .hardBoiledEggs]
case .tea: return [.greenTea, .blackTea]
case .workout: return [.runningSplits] case .workout: return [.runningSplits]
case .chill: return [.nap, .meditation] case .chill: return [.nap, .meditation]
case .other: return [.toothbrushing] case .other: return [.toothbrushing]
@ -30,6 +32,7 @@ enum PresetSection: Int, Identifiable, CaseIterable {
case .workout: return NSLocalizedString("Workout", comment: "") case .workout: return NSLocalizedString("Workout", comment: "")
case .chill: return NSLocalizedString("Chill", comment: "") case .chill: return NSLocalizedString("Chill", comment: "")
case .other: return NSLocalizedString("Other", comment: "") case .other: return NSLocalizedString("Other", comment: "")
case .tea: return NSLocalizedString("Tea", comment: "")
} }
} }
} }

Loading…
Cancel
Save