// // BlockingRule.swift // Severed // import Foundation import SwiftData /// A recurring screen-time blocking rule. /// /// Times are stored as minutes from midnight so the schedule repeats cleanly and /// is independent of time zones at creation. A window whose end is at or before /// its start (e.g. 22:00 → 06:00) crosses midnight into the following day. @Model final class BlockingRule { @Attribute(.unique) var id: UUID var name: String var kindRaw: String var isEnabled: Bool /// Hard block: while the rule is active it cannot be disabled, edited, or unblocked. var hardMode: Bool /// Engage Screen Time's adult-website filter while this rule is blocking. /// Inline default so existing stores migrate cleanly. var blockAdultContent: Bool = false var selectionModeRaw: String /// Encoded `FamilyActivitySelection` (opaque tokens). Nil until the user picks apps. var selectionData: Data? /// Denormalized count of selected apps/categories/domains for display. var selectionCount: Int var dayNumbers: [Int] var startMinutes: Int var endMinutes: Int /// Daily usage budget for `.timeLimit` rules. var dailyLimitMinutes: Int /// Daily open budget for `.openLimit` rules. var maxOpens: Int /// When set, the rule's current window is suspended (user tapped Unblock). /// Cleared automatically once the date passes; never set while Hard Mode is active. var pausedUntil: Date? var createdAt: Date init( id: UUID = UUID(), name: String, kind: RuleKind = .schedule, isEnabled: Bool = true, hardMode: Bool = false, blockAdultContent: Bool = false, selectionMode: SelectionMode = .block, selectionData: Data? = nil, selectionCount: Int = 0, days: Set = Weekday.weekdays, startMinutes: Int = 9 * 60, endMinutes: Int = 17 * 60, dailyLimitMinutes: Int = 45, maxOpens: Int = 5, pausedUntil: Date? = nil, createdAt: Date = .now ) { self.id = id self.name = name self.kindRaw = kind.rawValue self.isEnabled = isEnabled self.hardMode = hardMode self.blockAdultContent = blockAdultContent self.selectionModeRaw = selectionMode.rawValue self.selectionData = selectionData self.selectionCount = selectionCount self.dayNumbers = days.map(\.rawValue).sorted() self.startMinutes = startMinutes self.endMinutes = endMinutes self.dailyLimitMinutes = dailyLimitMinutes self.maxOpens = maxOpens self.pausedUntil = pausedUntil self.createdAt = createdAt } var kind: RuleKind { get { RuleKind(rawValue: kindRaw) ?? .schedule } set { kindRaw = newValue.rawValue } } var selectionMode: SelectionMode { get { SelectionMode(rawValue: selectionModeRaw) ?? .block } set { selectionModeRaw = newValue.rawValue } } var days: Set { get { Set(dayNumbers.compactMap(Weekday.init(rawValue:))) } set { dayNumbers = newValue.map(\.rawValue).sorted() } } var schedule: RuleSchedule { RuleSchedule(startMinutes: startMinutes, endMinutes: endMinutes, days: days) } }