115 lines
4.7 KiB
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)
|
|
}
|
|
}
|
|
}
|