- Shared/ layer compiled into the app and three new extension targets: rule snapshots in the app group, the usage ledger, monitoring-plan naming, and LimitEnforcement (shared, unit-tested event reactions) - RuleScheduler mirrors rules to the app group and reconciles DeviceActivity monitoring: one daily 00:00-23:59 activity per limit rule, with a cumulative usage-threshold event per budget minute for time limits; activities restart only when their configuration changes (a restart resets threshold accounting) - OpenAppLockMonitor (DeviceActivityMonitor): midnight budget resets, records usage minutes, shields at the budget, re-shields when a granted open session ends - OpenAppLockShieldConfig: open-limit shields show 'Opened X of N times today' with an 'Open (Y left)' secondary button - OpenAppLockShieldAction: an Open press spends one open, lifts the rule's shield, and starts the ~15-minute one-shot session - extensions are classic NSExtension app extensions (the ExtensionKit product type expects an @main entry and made the app fail to install); shield-store tracking moved to app-group defaults so the app and extensions see one consistent set - maps iOS 26's new .approvedWithDataAccess authorization status to approved (it previously fell through @unknown default to notDetermined) - shares the OpenAppLock scheme (Xcode dropped the autocreated one when targets were added) Co-Authored-By: Claude <noreply@anthropic.com>
65 lines
1.6 KiB
Swift
65 lines
1.6 KiB
Swift
//
|
|
// RuleKind.swift
|
|
// OpenAppLock
|
|
//
|
|
|
|
import Foundation
|
|
|
|
/// The three kinds of blocking rules, mirroring the reference app's "New Rule" sheet.
|
|
enum RuleKind: String, Codable, CaseIterable, Sendable {
|
|
/// Block selected apps during a recurring time window.
|
|
case schedule
|
|
/// Block selected apps after a daily usage budget is spent.
|
|
case timeLimit
|
|
/// Block selected apps after a number of opens per day.
|
|
case openLimit
|
|
|
|
var displayName: String {
|
|
switch self {
|
|
case .schedule: "Schedule"
|
|
case .timeLimit: "Time Limit"
|
|
case .openLimit: "Open Limit"
|
|
}
|
|
}
|
|
|
|
var exampleText: String {
|
|
switch self {
|
|
case .schedule: "e.g. 9-5, Daily"
|
|
case .timeLimit: "e.g. 45m/day"
|
|
case .openLimit: "e.g. 5 opens/day"
|
|
}
|
|
}
|
|
|
|
var symbolName: String {
|
|
switch self {
|
|
case .schedule: "calendar"
|
|
case .timeLimit: "hourglass"
|
|
case .openLimit: "lock.fill"
|
|
}
|
|
}
|
|
|
|
/// Default name given to a brand-new rule of this kind (Opal: "In the Zone", "Time Keeper").
|
|
var defaultRuleName: String {
|
|
switch self {
|
|
case .schedule: "In the Zone"
|
|
case .timeLimit: "Time Keeper"
|
|
case .openLimit: "Gate Keeper"
|
|
}
|
|
}
|
|
}
|
|
|
|
/// How the rule's app selection is interpreted.
|
|
enum SelectionMode: String, Codable, CaseIterable, Sendable {
|
|
/// Block the selected apps; everything else stays available.
|
|
case block
|
|
/// Block everything except the selected apps.
|
|
case allowOnly
|
|
|
|
var displayName: String {
|
|
switch self {
|
|
case .block: "Block"
|
|
case .allowOnly: "Allow Only"
|
|
}
|
|
}
|
|
}
|