import SwiftData import SwiftUI /// MixBoard iOS — A mobile music player and mix preparation tool. /// Listen to your own MP3/FLAC files, build playlists, and sync them to the Mac app for DAW export. @main struct MixBoardApp: App { @State private var playerVM = PlayerViewModel() @State private var playlistVM = PlaylistViewModel() @StateObject private var libraryManager = LibraryManager() @StateObject private var theme = AppTheme() @StateObject private var syncManager = SyncManager() let modelContainer: ModelContainer init() { // One-time database reset to clear corrupted Track/p2 data + add cloud fields let needsReset = !UserDefaults.standard.bool(forKey: "dbResetV7") if needsReset { // Nuclear option: find and delete ALL .store and .sqlite files in the app container let fm = FileManager.default let home = fm.urls(for: .libraryDirectory, in: .userDomainMask).first! .deletingLastPathComponent() // gets the app container root if let enumerator = fm.enumerator(at: home, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles]) { for case let fileURL as URL in enumerator { let name = fileURL.lastPathComponent if name == "default.store" || name == "default.store-shm" || name == "default.store-wal" || name.hasSuffix(".sqlite") || name.hasSuffix(".sqlite-shm") || name.hasSuffix(".sqlite-wal") { try? fm.removeItem(at: fileURL) } } } UserDefaults.standard.set(true, forKey: "dbResetV7") } do { modelContainer = try ModelContainer(for: Track.self, CuePoint.self, Playlist.self, PlaylistEntry.self, PlaylistFolder.self) } catch { fatalError("Failed to create ModelContainer: \(error)") } // Clean up leftover mock state for non-mock UI tests if ProcessInfo.processInfo.arguments.contains("-UITesting") && !ProcessInfo.processInfo.arguments.contains("-MockNetwork") { UserDefaults.standard.removeObject(forKey: "chadMusic.serverURL") KeychainService.deleteAPIKey() } // Register mock URL protocol for CI/UI testing with stubbed network if ProcessInfo.processInfo.arguments.contains("-MockNetwork") { MockURLProtocol.registerMockResponses() // Set dummy server config so the API client considers itself configured UserDefaults.standard.set("http://localhost:9999", forKey: "chadMusic.serverURL") try? KeychainService.saveAPIKey("mock-test-key") } } var body: some Scene { WindowGroup { ContentView() .environment(playerVM) .environment(playlistVM) .environmentObject(libraryManager) .environmentObject(theme) .environmentObject(syncManager) .preferredColorScheme(theme.preferredColorScheme) .onAppear { MediaKeyHandler.shared.register(playerVM: playerVM) } } .modelContainer(modelContainer) } }