Files
OpenAppLock/OpenAppLock/OpenAppLockApp.swift
Brendan Chen 8e3b8b70f5 feat: track limit budgets in a usage ledger and surface them in a Usage section
- RuleUsage + UsageLedger: per-rule, per-day minutes/opens in app-group
  defaults (monotonic minutes, incrementing opens, midnight rollover by
  day-keying); MockUsageLedger for tests and seeded UI scenarios
- usage-aware status: a limit rule whose daily budget is spent on an
  enabled day is active (blocking) until next midnight; Hard Mode gating
  and app-list locking honor it; soft unblock pauses until midnight
- RuleEnforcer shields spent limit rules (always Block mode) while the
  app runs
- new Usage section under Blocked Apps: '18m of 45m used today · 27m
  left', '2 of 5 opens today · 3 opens left', 'Blocked until tomorrow'
- new 'limits' seed scenario + UI tests
2026-06-12 20:22:48 -04:00

65 lines
2.1 KiB
Swift

//
// OpenAppLockApp.swift
// OpenAppLock
//
// Created by Brendan Chen on 2025.08.09.
//
import SwiftData
import SwiftUI
@main
struct OpenAppLockApp: App {
private let container: ModelContainer
@State private var authorization: ScreenTimeAuthorization
@State private var enforcer: RuleEnforcer
init() {
let config = LaunchConfiguration.current
if let onboardingCompleted = config.onboardingCompleted {
UserDefaults.standard.set(onboardingCompleted, forKey: "hasCompletedOnboarding")
}
let schema = Schema([BlockingRule.self, AppList.self])
let modelConfiguration = ModelConfiguration(
schema: schema, isStoredInMemoryOnly: config.isUITesting
)
do {
container = try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
let usageLedger: UsageReading = config.isUITesting ? MockUsageLedger() : UsageLedger()
if let scenario = config.seedScenario {
SampleRules.seed(
scenario, into: container.mainContext, usage: usageLedger as? MockUsageLedger
)
}
AppListMigration.run(in: container.mainContext)
let authProvider: AuthorizationProviding =
config.isUITesting
? MockAuthorizationProvider(
status: config.onboardingCompleted == false ? .notDetermined : .approved
)
: FamilyControlsAuthorizationProvider()
_authorization = State(initialValue: ScreenTimeAuthorization(provider: authProvider))
let shields: ShieldApplying =
config.isUITesting ? MockShieldController() : ManagedSettingsShieldController()
_enforcer = State(initialValue: RuleEnforcer(shields: shields, usage: usageLedger))
}
var body: some Scene {
WindowGroup {
RootView()
.environment(authorization)
.environment(enforcer)
}
.modelContainer(container)
}
}