BusinessCard/BusinessCard/BusinessCardApp.swift

121 lines
4.7 KiB
Swift

import SwiftUI
import SwiftData
import AppIntents
import Bedrock
@main
struct BusinessCardApp: App {
private let modelContainer: ModelContainer
@State private var appState: AppState
init() {
let schema = Schema([BusinessCard.self, Contact.self, ContactField.self, AppSettings.self])
let cloudKitDatabase: ModelConfiguration.CloudKitDatabase =
AppIdentifiers.isCloudKitSyncEnabled
? .private(AppIdentifiers.cloudKitContainerIdentifier)
: .none
// Register app theme for Bedrock semantic text/surface colors.
Theme.register(
text: AppThemeText.self,
surface: AppSurface.self,
accent: AppThemeAccent.self,
status: AppStatus.self
)
Theme.register(border: AppBorder.self)
// Primary strategy: App Group-backed persistent store.
var container: ModelContainer?
func makeContainer(storeURL: URL, cloudKitDatabase: ModelConfiguration.CloudKitDatabase) -> ModelContainer? {
let config = ModelConfiguration(
schema: schema,
url: storeURL,
cloudKitDatabase: cloudKitDatabase
)
return try? ModelContainer(for: schema, configurations: [config])
}
if let appGroupURL = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: AppIdentifiers.appGroupIdentifier
) {
let storeURL = appGroupURL.appending(path: "BusinessCard.store")
container = makeContainer(storeURL: storeURL, cloudKitDatabase: cloudKitDatabase)
if container == nil {
Design.debugLog("Failed to create container in App Group.")
}
}
// Fallback: Default location (Application Support)
if container == nil {
let storeURL = URL.applicationSupportDirectory.appending(path: "BusinessCard.store")
container = makeContainer(storeURL: storeURL, cloudKitDatabase: cloudKitDatabase)
if container == nil {
Design.debugLog("Failed to create container in Application Support.")
}
}
// If CloudKit mode fails, force local-on-disk fallback before in-memory.
if container == nil && AppIdentifiers.isCloudKitSyncEnabled {
if let appGroupURL = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: AppIdentifiers.appGroupIdentifier
) {
let storeURL = appGroupURL.appending(path: "BusinessCard.store")
container = makeContainer(storeURL: storeURL, cloudKitDatabase: .none)
if container == nil {
Design.debugLog("Failed to create local-only container in App Group.")
}
}
if container == nil {
let storeURL = URL.applicationSupportDirectory.appending(path: "BusinessCard.store")
container = makeContainer(storeURL: storeURL, cloudKitDatabase: .none)
if container == nil {
Design.debugLog("Failed to create local-only container in Application Support.")
}
}
}
// Last resort: In-memory (data won't persist but app will work)
if container == nil {
Design.debugLog("WARNING: Using in-memory store - data will not persist!")
let config = ModelConfiguration(
schema: schema,
isStoredInMemoryOnly: true,
cloudKitDatabase: .none
)
container = try? ModelContainer(for: schema, configurations: [config])
}
guard let container else {
fatalError("Failed to create ModelContainer with all strategies")
}
self.modelContainer = container
let context = container.mainContext
self._appState = State(initialValue: AppState(modelContext: context))
// Activate WatchConnectivity session
_ = WatchConnectivityService.shared
}
var body: some Scene {
WindowGroup {
ZStack {
// Base background matching launch screen - prevents white flash
Color.Branding.primary
.ignoresSafeArea()
AppLaunchView(config: .businessCard) {
RootTabView()
.environment(appState)
.preferredColorScheme(appState.preferredColorScheme)
.autocorrectionDisabled(true)
.textInputAutocapitalization(.sentences)
}
}
}
.modelContainer(modelContainer)
}
}