Andromida/Andromida/AndromidaApp.swift

115 lines
4.7 KiB
Swift

import SwiftUI
import SwiftData
import Bedrock
@main
struct AndromidaApp: App {
private let modelContainer: ModelContainer
@State private var store: RitualStore
@State private var settingsStore: SettingsStore
@State private var categoryStore: CategoryStore
@AppStorage("hasCompletedSetupWizard") private var hasCompletedSetupWizard = false
/// Track if user just completed the wizard (to start on Rituals tab)
@State private var justCompletedWizard = false
@State private var isTransitioningToRoot = false
init() {
// Register app's color theme for Bedrock components
Theme.register(
text: AppTextColors.self,
surface: AppSurface.self,
accent: AppAccent.self,
status: AppStatus.self
)
Theme.register(border: AppBorder.self)
let environment = ProcessInfo.processInfo.environment
let isRunningTests = environment["XCTestConfigurationFilePath"] != nil
let isUITesting = environment["UITEST_MODE"] == "1"
if isUITesting {
if environment["UITEST_RESET_USER_DEFAULTS"] == "1",
let bundleIdentifier = Bundle.main.bundleIdentifier {
UserDefaults.standard.removePersistentDomain(forName: bundleIdentifier)
}
if let completedValue = environment["UITEST_HAS_COMPLETED_SETUP_WIZARD"] {
let hasCompleted = completedValue == "1" || completedValue.lowercased() == "true"
UserDefaults.standard.set(hasCompleted, forKey: "hasCompletedSetupWizard")
}
}
// Include all models in schema - Ritual, RitualArc, and ArcHabit
let schema = Schema([Ritual.self, RitualArc.self, ArcHabit.self])
let configuration: ModelConfiguration
if isUITesting {
// UI tests should always run with isolated in-memory persistence.
configuration = ModelConfiguration(
schema: schema,
isStoredInMemoryOnly: true,
cloudKitDatabase: .none
)
} else {
// Use App Group for shared container between app and widget.
// Disable CloudKit mirroring under XCTest to keep simulator tests deterministic.
let storeURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: AppIdentifiers.appGroupIdentifier)?
.appendingPathComponent("Andromida.sqlite") ?? URL.documentsDirectory.appendingPathComponent("Andromida.sqlite")
configuration = ModelConfiguration(
schema: schema,
url: storeURL,
cloudKitDatabase: isRunningTests ? .none : .private(AppIdentifiers.cloudKitContainerIdentifier)
)
}
let container: ModelContainer
do {
container = try ModelContainer(for: schema, configurations: [configuration])
} catch {
fatalError("Unable to create model container: \(error)")
}
modelContainer = container
let settings = SettingsStore()
_settingsStore = State(initialValue: settings)
_categoryStore = State(initialValue: CategoryStore())
_store = State(initialValue: RitualStore(modelContext: container.mainContext, seedService: RitualSeedService(), settingsStore: settings))
}
var body: some Scene {
WindowGroup {
ZStack {
Color.Branding.primary
.ignoresSafeArea()
if hasCompletedSetupWizard {
// Main app - start on Rituals tab if just completed wizard
RootView(
store: store,
settingsStore: settingsStore,
categoryStore: categoryStore,
initialTab: justCompletedWizard ? .rituals : .today
)
.transition(.opacity)
} else {
// First-run setup wizard
AppLaunchView(config: .rituals) {
SetupWizardView(
store: store,
categoryStore: categoryStore,
reminderScheduler: store.reminderScheduler,
onComplete: {
justCompletedWizard = true
withAnimation(.easeInOut(duration: 0.5)) {
hasCompletedSetupWizard = true
}
}
)
}
}
}
.modelContainer(modelContainer)
.preferredColorScheme(settingsStore.theme.colorScheme)
}
}
}