diff --git a/OnCue.xcodeproj/project.pbxproj b/OnCue.xcodeproj/project.pbxproj index 27b0523..e38f32d 100644 --- a/OnCue.xcodeproj/project.pbxproj +++ b/OnCue.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 460D7DF62C2AE788002B623C /* TimerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 460D7DF52C2AE788002B623C /* TimerManager.swift */; }; 460D7DF72C2AE788002B623C /* TimerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 460D7DF52C2AE788002B623C /* TimerManager.swift */; }; + 4614D4032C3DFD3E000799F5 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D3E1432C27DFCE0060722E /* Preferences.swift */; }; 464787CB2C269CAF00A9C462 /* TeleprompterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 464787CA2C269CAF00A9C462 /* TeleprompterView.swift */; }; 464787CC2C26A2E100A9C462 /* ColorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46AD30F12C2672BD00486C25 /* ColorModel.swift */; }; 464787CD2C26A2E500A9C462 /* PreviewData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46AD30F32C267D6400486C25 /* PreviewData.swift */; }; @@ -67,6 +68,8 @@ /* Begin PBXFileReference section */ 460D7DF52C2AE788002B623C /* TimerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerManager.swift; sourceTree = ""; }; 4614D4022C3DF680000799F5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 4614D4042C3DFEE8000799F5 /* OnCuePresenter.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OnCuePresenter.entitlements; sourceTree = ""; }; + 4614D4052C3DFF16000799F5 /* OnCuePresenter-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "OnCuePresenter-Info.plist"; sourceTree = ""; }; 464787CA2C269CAF00A9C462 /* TeleprompterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeleprompterView.swift; sourceTree = ""; }; 46AD30B72C26557500486C25 /* OnCue.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OnCue.app; sourceTree = BUILT_PRODUCTS_DIR; }; 46AD30BA2C26557500486C25 /* OnCueApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnCueApp.swift; sourceTree = ""; }; @@ -116,6 +119,8 @@ 46AD30AE2C26557500486C25 = { isa = PBXGroup; children = ( + 4614D4052C3DFF16000799F5 /* OnCuePresenter-Info.plist */, + 4614D4042C3DFEE8000799F5 /* OnCuePresenter.entitlements */, 46AD30F02C2672AC00486C25 /* Shared */, 46AD30B92C26557500486C25 /* OnCue */, 46AD30CF2C26559B00486C25 /* OnCuePresenter Watch App */, @@ -355,6 +360,7 @@ files = ( 46AD30E32C2656CB00486C25 /* OCCard.swift in Sources */, 46AD30D32C26559B00486C25 /* MainViewPresenter.swift in Sources */, + 4614D4032C3DFD3E000799F5 /* Preferences.swift in Sources */, 46E5FFD92C26A50D001191C9 /* CueCardViewPresenter.swift in Sources */, 464787CD2C26A2E500A9C462 /* PreviewData.swift in Sources */, 46AD30D12C26559B00486C25 /* OnCuePresenterApp.swift in Sources */, @@ -574,12 +580,14 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = OnCuePresenter.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"OnCuePresenter Watch App/Preview Content\""; DEVELOPMENT_TEAM = 9MP5435PRF; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "OnCuePresenter-Info.plist"; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; INFOPLIST_KEY_WKCompanionAppBundleIdentifier = xyz.breadone.oncue; LD_RUNPATH_SEARCH_PATHS = ( @@ -587,14 +595,14 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = xyz.breadone.oncue.watchkitapp; + PRODUCT_BUNDLE_IDENTIFIER = xyz.breadone.oncue.presenter; PRODUCT_NAME = OnCue; SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 10.5; + WATCHOS_DEPLOYMENT_TARGET = 10.0; }; name = Debug; }; @@ -603,12 +611,14 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = OnCuePresenter.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"OnCuePresenter Watch App/Preview Content\""; DEVELOPMENT_TEAM = 9MP5435PRF; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "OnCuePresenter-Info.plist"; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; INFOPLIST_KEY_WKCompanionAppBundleIdentifier = xyz.breadone.oncue; LD_RUNPATH_SEARCH_PATHS = ( @@ -616,14 +626,14 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = xyz.breadone.oncue.watchkitapp; + PRODUCT_BUNDLE_IDENTIFIER = xyz.breadone.oncue.presenter; PRODUCT_NAME = OnCue; SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 10.5; + WATCHOS_DEPLOYMENT_TARGET = 10.0; }; name = Release; }; diff --git a/OnCue/Info.plist b/OnCue/Info.plist index ca9a074..26fa09f 100644 --- a/OnCue/Info.plist +++ b/OnCue/Info.plist @@ -4,6 +4,7 @@ UIBackgroundModes + fetch remote-notification diff --git a/OnCue/Model/OCCard.swift b/OnCue/Model/OCCard.swift index cfb292d..c047b6c 100644 --- a/OnCue/Model/OCCard.swift +++ b/OnCue/Model/OCCard.swift @@ -15,8 +15,9 @@ final class OCCard: Identifiable { var index: Int = 0 var parentProject: OCProject? = nil - init(content: String, index: Int) { + init(content: String, index: Int, parent: OCProject) { self.content = content self.index = index + self.parentProject = parent } } diff --git a/OnCue/Model/OCProject.swift b/OnCue/Model/OCProject.swift index bdcff95..b3e6a1e 100644 --- a/OnCue/Model/OCProject.swift +++ b/OnCue/Model/OCProject.swift @@ -37,6 +37,17 @@ final class OCProject { self.color = color } + init(name: String, color: String, tCards: [String] = []) { + self.name = name + self.creationDate = Date() + self.lastEditedDate = Date() + self.color = color + + for i in 0 ..< tCards.count { + self.cards?.append(OCCard(content: tCards[i], index: i, parent: self)) + } + } + func updateEditedDate(newDate: Date = Date()) { self.lastEditedDate = newDate } diff --git a/OnCue/OnCueApp.swift b/OnCue/OnCueApp.swift index cb2a8f8..cafe1f1 100644 --- a/OnCue/OnCueApp.swift +++ b/OnCue/OnCueApp.swift @@ -20,33 +20,33 @@ struct OnCueApp: App { let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { -// #if DEBUG -// // Use an autorelease pool to make sure Swift deallocates the persistent -// // container before setting up the SwiftData stack. -// try autoreleasepool { -// let desc = NSPersistentStoreDescription(url: modelConfiguration.url) -// let opts = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.xyz.breadone.oncue") -// desc.cloudKitContainerOptions = opts -// // Load the store synchronously so it completes before initializing the -// // CloudKit schema. -// desc.shouldAddStoreAsynchronously = false -// if let mom = NSManagedObjectModel.makeManagedObjectModel(for: [OCProject.self, OCCard.self]) { -// let container = NSPersistentCloudKitContainer(name: "OnCue", managedObjectModel: mom) -// container.persistentStoreDescriptions = [desc] -// container.loadPersistentStores {_, err in -// if let err { -// fatalError(err.localizedDescription) -// } -// } -// // Initialize the CloudKit schema after the store finishes loading. -// try container.initializeCloudKitSchema() -// // Remove and unload the store from the persistent container. -// if let store = container.persistentStoreCoordinator.persistentStores.first { -// try container.persistentStoreCoordinator.remove(store) -// } -// } -// } -// #endif + #if DEBUG + // Use an autorelease pool to make sure Swift deallocates the persistent + // container before setting up the SwiftData stack. + try autoreleasepool { + let desc = NSPersistentStoreDescription(url: modelConfiguration.url) + let opts = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.xyz.breadone.oncue") + desc.cloudKitContainerOptions = opts + // Load the store synchronously so it completes before initializing the + // CloudKit schema. + desc.shouldAddStoreAsynchronously = false + if let mom = NSManagedObjectModel.makeManagedObjectModel(for: [OCProject.self, OCCard.self]) { + let container = NSPersistentCloudKitContainer(name: "OnCue", managedObjectModel: mom) + container.persistentStoreDescriptions = [desc] + container.loadPersistentStores {_, err in + if let err { + fatalError(err.localizedDescription) + } + } + // Initialize the CloudKit schema after the store finishes loading. + try container.initializeCloudKitSchema() + // Remove and unload the store from the persistent container. + if let store = container.persistentStoreCoordinator.persistentStores.first { + try container.persistentStoreCoordinator.remove(store) + } + } + } + #endif return try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { diff --git a/OnCue/View/CardsView.swift b/OnCue/View/CardsView.swift index bd40419..aecb547 100644 --- a/OnCue/View/CardsView.swift +++ b/OnCue/View/CardsView.swift @@ -84,9 +84,12 @@ struct CardsView: View { return } - let card = OCCard(content: txt, index: (project.sortedCards.last?.index ?? -1) + 1) // adds one to the index, unless there arent any cards in which case default to 0 + // adds one to the index, unless there arent any cards in which case default to 0 + let card = OCCard(content: txt, + index: (project.sortedCards.last?.index ?? -1) + 1, + parent: project) project.cards?.append(card) - try! ctx.save() + try? ctx.save() newCardText = "" } diff --git a/OnCue/View/MainView.swift b/OnCue/View/MainView.swift index 872b505..f052090 100644 --- a/OnCue/View/MainView.swift +++ b/OnCue/View/MainView.swift @@ -60,7 +60,7 @@ struct MainView: View { // } else { // newProject = OCProject(name: name, color: color) // } - newProject = OCProject(name: name, color: color) + newProject = OCProject(name: name, color: color, cards: []) modelContext.insert(newProject) } } diff --git a/OnCuePresenter Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json b/OnCuePresenter Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json index 49c81cd..45dc927 100644 --- a/OnCuePresenter Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/OnCuePresenter Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,6 +1,7 @@ { "images" : [ { + "filename" : "oncue_icon.png", "idiom" : "universal", "platform" : "watchos", "size" : "1024x1024" diff --git a/OnCuePresenter Watch App/Assets.xcassets/AppIcon.appiconset/oncue_icon.png b/OnCuePresenter Watch App/Assets.xcassets/AppIcon.appiconset/oncue_icon.png new file mode 100644 index 0000000..a81f24a Binary files /dev/null and b/OnCuePresenter Watch App/Assets.xcassets/AppIcon.appiconset/oncue_icon.png differ diff --git a/OnCuePresenter Watch App/OnCuePresenterApp.swift b/OnCuePresenter Watch App/OnCuePresenterApp.swift index 5f9afca..81f6dfa 100644 --- a/OnCuePresenter Watch App/OnCuePresenterApp.swift +++ b/OnCuePresenter Watch App/OnCuePresenterApp.swift @@ -7,6 +7,7 @@ import SwiftUI import SwiftData +import CoreData @main struct OnCuePresenter_Watch_AppApp: App { @@ -14,11 +15,37 @@ struct OnCuePresenter_Watch_AppApp: App { let schema = Schema([ OCProject.self, OCCard.self, -// Item.self, ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { + #if DEBUG + // Use an autorelease pool to make sure Swift deallocates the persistent + // container before setting up the SwiftData stack. + try autoreleasepool { + let desc = NSPersistentStoreDescription(url: modelConfiguration.url) + let opts = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.xyz.breadone.oncue") + desc.cloudKitContainerOptions = opts + // Load the store synchronously so it completes before initializing the + // CloudKit schema. + desc.shouldAddStoreAsynchronously = false + if let mom = NSManagedObjectModel.makeManagedObjectModel(for: [OCProject.self, OCCard.self]) { + let container = NSPersistentCloudKitContainer(name: "OnCue", managedObjectModel: mom) + container.persistentStoreDescriptions = [desc] + container.loadPersistentStores {_, err in + if let err { + fatalError(err.localizedDescription) + } + } + // Initialize the CloudKit schema after the store finishes loading. + try container.initializeCloudKitSchema() + // Remove and unload the store from the persistent container. + if let store = container.persistentStoreCoordinator.persistentStores.first { + try container.persistentStoreCoordinator.remove(store) + } + } + } + #endif return try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { fatalError("Could not create ModelContainer: \(error)") diff --git a/OnCuePresenter Watch App/View/MainViewPresenter.swift b/OnCuePresenter Watch App/View/MainViewPresenter.swift index 8d8ff31..927729d 100644 --- a/OnCuePresenter Watch App/View/MainViewPresenter.swift +++ b/OnCuePresenter Watch App/View/MainViewPresenter.swift @@ -12,6 +12,7 @@ struct MainViewPresenter: View { @Environment(\.modelContext) private var modelContext @Query private var items: [OCProject] + @AppStorage(Preferences.themeColour) var themeColor = Color.blue.toHex()! @State private var newProjectName = "" @State private var addNewProject = false @@ -23,13 +24,19 @@ struct MainViewPresenter: View { CueCardViewPresenter(project: project) } label: { VStack(alignment: .leading) { - Text("\(project.name)") - .bold() - .font(.title2) - .foregroundStyle(Color(hex: project.color) ?? .white) + if (project.color == Color.clear.toHex()!) { + Text("\(project.name)") + .bold() + .font(.title2) + .foregroundStyle(Color(hex: themeColor) ?? .blue) + } else { + Text("\(project.name)") + .bold() + .font(.title2) + .foregroundStyle(Color(hex: project.color) ?? .white) + } Text("\(project.cards?.count ?? 0) \(project.cards?.count ?? 0 == 1 ? "Card" : "Cards")") - } - } + } } .padding(.vertical, 3) } diff --git a/OnCuePresenter-Info.plist b/OnCuePresenter-Info.plist new file mode 100644 index 0000000..ca9a074 --- /dev/null +++ b/OnCuePresenter-Info.plist @@ -0,0 +1,10 @@ + + + + + UIBackgroundModes + + remote-notification + + + diff --git a/OnCuePresenter.entitlements b/OnCuePresenter.entitlements new file mode 100644 index 0000000..9f5c100 --- /dev/null +++ b/OnCuePresenter.entitlements @@ -0,0 +1,16 @@ + + + + + aps-environment + development + com.apple.developer.icloud-container-identifiers + + iCloud.xyz.breadone.oncue + + com.apple.developer.icloud-services + + CloudKit + + + diff --git a/Shared/PreviewData.swift b/Shared/PreviewData.swift index 201c876..cd633cb 100644 --- a/Shared/PreviewData.swift +++ b/Shared/PreviewData.swift @@ -12,16 +12,5 @@ public struct PreviewData { private static let lorem = "colon three" - static let project = OCProject(name: "Test Project", color: "007AFF", cards: [ - OCCard(content: lorem, index: 0), - OCCard(content: lorem, index: 1), - OCCard(content: lorem, index: 2), - OCCard(content: loreml, index: 3), - OCCard(content: lorem, index: 4), - OCCard(content: lorem, index: 5), - OCCard(content: lorem, index: 6), - OCCard(content: lorem, index: 7), - OCCard(content: lorem, index: 8), - OCCard(content: lorem, index: 9), - ]) + static let project = OCProject(name: "Test Project", color: "007AFF", tCards: Array(repeating: lorem, count: 10) ) }