- 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>
66 lines
2.0 KiB
Swift
66 lines
2.0 KiB
Swift
//
|
|
// Weekday.swift
|
|
// OpenAppLock
|
|
//
|
|
|
|
import Foundation
|
|
|
|
/// A day of the week, using `Calendar` weekday numbering (1 = Sunday … 7 = Saturday).
|
|
enum Weekday: Int, CaseIterable, Codable, Hashable, Sendable {
|
|
case sunday = 1
|
|
case monday = 2
|
|
case tuesday = 3
|
|
case wednesday = 4
|
|
case thursday = 5
|
|
case friday = 6
|
|
case saturday = 7
|
|
|
|
static let weekdays: Set<Weekday> = [.monday, .tuesday, .wednesday, .thursday, .friday]
|
|
static let weekends: Set<Weekday> = [.saturday, .sunday]
|
|
static let everyDay: Set<Weekday> = Set(Weekday.allCases)
|
|
|
|
/// Display order used by the day picker, matching the reference UI: S M T W T F S.
|
|
static let displayOrder: [Weekday] = [
|
|
.sunday, .monday, .tuesday, .wednesday, .thursday, .friday, .saturday,
|
|
]
|
|
|
|
/// Single-letter label for the circular day toggles.
|
|
var shortLabel: String {
|
|
switch self {
|
|
case .sunday, .saturday: "S"
|
|
case .monday: "M"
|
|
case .tuesday, .thursday: "T"
|
|
case .wednesday: "W"
|
|
case .friday: "F"
|
|
}
|
|
}
|
|
|
|
/// Three-letter abbreviation used in custom day summaries ("Mon, Wed, Fri").
|
|
var abbreviation: String {
|
|
switch self {
|
|
case .sunday: "Sun"
|
|
case .monday: "Mon"
|
|
case .tuesday: "Tue"
|
|
case .wednesday: "Wed"
|
|
case .thursday: "Thu"
|
|
case .friday: "Fri"
|
|
case .saturday: "Sat"
|
|
}
|
|
}
|
|
}
|
|
|
|
extension Set<Weekday> {
|
|
/// Human-readable summary shown next to the day picker and in rule details:
|
|
/// "Weekdays", "Weekends", "Every day", "Never", or a list like "Mon, Wed, Fri".
|
|
var summary: String {
|
|
if self == Weekday.everyDay { return "Every day" }
|
|
if self == Weekday.weekdays { return "Weekdays" }
|
|
if self == Weekday.weekends { return "Weekends" }
|
|
if isEmpty { return "Never" }
|
|
return Weekday.displayOrder
|
|
.filter(contains)
|
|
.map(\.abbreviation)
|
|
.joined(separator: ", ")
|
|
}
|
|
}
|