- Add Block Adult Content toggle to all three rule editors, persisted as BlockingRule.blockAdultContent (inline default for clean migration of existing stores) and surfaced in the detail sheet as an 'Adult websites: Blocked/Allowed' row - Engage Screen Time's adult-website filter (webContent.blockedByFilter = .auto()) alongside the rule's shield and clear it when the shield clears - Replace the New Rule sheet's view-swap with a NavigationStack push (navigationDestination(item:)); the editor uses native chrome there (system back button, inline title, toolbar rename), enabling the push animation and edge-swipe back - Tests: 93 passing (+2 unit: draft round-trip and enforcer forwarding; +3 UI: toggle-to-detail flow, default-allowed row, swipe-back as a behavioral proof of native navigation) - Spec updated accordingly (editor sections, behavior, data model, navigation note)
90 lines
2.7 KiB
Swift
90 lines
2.7 KiB
Swift
//
|
||
// RuleDraft.swift
|
||
// Severed
|
||
//
|
||
|
||
import Foundation
|
||
|
||
/// Value-type working copy of a rule used by the editors, so cancelling an
|
||
/// edit never touches the persisted model. Hashable so it can drive
|
||
/// `navigationDestination(item:)`.
|
||
struct RuleDraft: Hashable {
|
||
var name: String
|
||
var kind: RuleKind
|
||
var days: Set<Weekday>
|
||
var startMinutes: Int
|
||
var endMinutes: Int
|
||
var dailyLimitMinutes: Int
|
||
var maxOpens: Int
|
||
var hardMode: Bool
|
||
var blockAdultContent: Bool
|
||
var selectionMode: SelectionMode
|
||
var selectionData: Data?
|
||
var selectionCount: Int
|
||
|
||
/// A fresh draft for a new rule of the given kind, using the reference
|
||
/// app's defaults (9–5 weekdays schedule, 45m/day, 5 opens/day).
|
||
init(kind: RuleKind) {
|
||
self.name = kind.defaultRuleName
|
||
self.kind = kind
|
||
self.days = Weekday.weekdays
|
||
self.startMinutes = 9 * 60
|
||
self.endMinutes = 17 * 60
|
||
self.dailyLimitMinutes = 45
|
||
self.maxOpens = 5
|
||
self.hardMode = false
|
||
self.blockAdultContent = false
|
||
self.selectionMode = .block
|
||
self.selectionData = nil
|
||
self.selectionCount = 0
|
||
}
|
||
|
||
init(rule: BlockingRule) {
|
||
self.name = rule.name
|
||
self.kind = rule.kind
|
||
self.days = rule.days
|
||
self.startMinutes = rule.startMinutes
|
||
self.endMinutes = rule.endMinutes
|
||
self.dailyLimitMinutes = rule.dailyLimitMinutes
|
||
self.maxOpens = rule.maxOpens
|
||
self.hardMode = rule.hardMode
|
||
self.blockAdultContent = rule.blockAdultContent
|
||
self.selectionMode = rule.selectionMode
|
||
self.selectionData = rule.selectionData
|
||
self.selectionCount = rule.selectionCount
|
||
}
|
||
|
||
init(preset: RulePreset) {
|
||
self.init(kind: .schedule)
|
||
self.name = preset.name
|
||
self.days = preset.days
|
||
self.startMinutes = preset.startMinutes
|
||
self.endMinutes = preset.endMinutes
|
||
}
|
||
|
||
func apply(to rule: BlockingRule) {
|
||
rule.name = name
|
||
rule.kind = kind
|
||
rule.days = days
|
||
rule.startMinutes = startMinutes
|
||
rule.endMinutes = endMinutes
|
||
rule.dailyLimitMinutes = dailyLimitMinutes
|
||
rule.maxOpens = maxOpens
|
||
rule.hardMode = hardMode
|
||
rule.blockAdultContent = blockAdultContent
|
||
rule.selectionMode = selectionMode
|
||
rule.selectionData = selectionData
|
||
rule.selectionCount = selectionCount
|
||
}
|
||
|
||
func makeRule() -> BlockingRule {
|
||
let rule = BlockingRule(name: name, kind: kind)
|
||
apply(to: rule)
|
||
return rule
|
||
}
|
||
|
||
var schedule: RuleSchedule {
|
||
RuleSchedule(startMinutes: startMinutes, endMinutes: endMinutes, days: days)
|
||
}
|
||
}
|