// // WorkoutsApp.swift // Workouts // // Copyright 2025 Rouslan Zenetl. All Rights Reserved. // import SwiftUI import SwiftData import UIKit @main struct WorkoutsApp: App { @State private var services = AppServices() @Environment(\.scenePhase) private var scenePhase var body: some Scene { WindowGroup { #if DEBUG if ScreenshotSeed.isActive { ScreenshotRootView(services: services) } else { root } #else root #endif } // Keep the screen lit for the whole app, not just while logging — the phone is // often propped up across the room during a workout. iOS clears this flag when // the app is backgrounded, so re-assert it each time the scene becomes active. .onChange(of: scenePhase, initial: true) { _, phase in UIApplication.shared.isIdleTimerDisabled = (phase == .active) // An editor left open when the app leaves the foreground must not keep the // watch's run parked ("Editing on iPhone…") — suspend the published edit // locks while backgrounded; returning to the editor re-asserts them. services.watchBridge.setLocksSuspended(phase != .active) // Last chance before suspension: push any queued document writes out // now rather than waiting out a retry backoff we may not live to see. if phase == .background { Task { await services.syncEngine.flushPendingWrites() } } } } private var root: some View { RootGateView() .environment(services) .environment(services.syncEngine) .environment(services.liveRunState) .modelContainer(services.container) .task { await services.bootstrap() } // Tap a shared ".workoutsbackup" file (Files, AirDrop, share sheet) to // restore it. The controller stops the sync observer for the restore and // rebuilds the cache afterward (see AppBackupConfiguration). .onOpenURL { url in guard url.pathExtension == "workoutsbackup" else { return } Task { try? await services.backupController.restoreBackup(from: url) } } } }