From 44e6086e297c83fbab2eb66b88c62c4e039f17fc Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sat, 13 Jun 2026 22:32:05 -0400 Subject: [PATCH] feat: replace the preset gallery with original schedules Swap the six suggested rules for an original set so the preset offerings are OpenAppLock's own: - Focus Time: Morning Focus (08:00-11:30 weekdays), Deep Work (13:30-16:00 weekdays) - Rest & Recharge: Evening Reset (21:00-23:00), Lights Out (23:00-06:30, crosses midnight) - Healthy Balance: Family Dinner (18:00-19:30), Screen-Free Sunday (09:00-20:00, Sundays) Update the spec preset gallery (sections 1, 3.3, 4) and the preset unit/UI tests to the new ids, names, and times. Build green; the preset draft unit test and the two preset UI tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) --- OpenAppLock/Models/RulePreset.swift | 58 ++++++++++---------- OpenAppLockTests/RuleModelTests.swift | 8 +-- OpenAppLockUITests/RuleCreationUITests.swift | 12 ++-- docs/RULES_FEATURE_SPEC.md | 24 ++++---- 4 files changed, 51 insertions(+), 51 deletions(-) diff --git a/OpenAppLock/Models/RulePreset.swift b/OpenAppLock/Models/RulePreset.swift index a350047..aa92176 100644 --- a/OpenAppLock/Models/RulePreset.swift +++ b/OpenAppLock/Models/RulePreset.swift @@ -22,7 +22,7 @@ struct RulePreset: Identifiable, Hashable, Sendable { } } -/// A titled group of presets ("Get More Done", "Sleep, Relax and Reset", …). +/// A titled group of presets ("Focus Time", "Rest & Recharge", …). struct RulePresetSection: Identifiable, Hashable, Sendable { let id: String let title: String @@ -31,20 +31,20 @@ struct RulePresetSection: Identifiable, Hashable, Sendable { static let all: [RulePresetSection] = [ RulePresetSection( - id: "productivity", - title: "Get More Done", - subtitle: "Maximize your productivity while staying sane.", + id: "focus", + title: "Focus Time", + subtitle: "Protect your deep-work hours.", presets: [ RulePreset( - id: "work-time", name: "Work Time", - startMinutes: 9 * 60, endMinutes: 17 * 60, days: Weekday.weekdays, - symbolName: "briefcase.fill", - gradientTop: Color(red: 0.16, green: 0.27, blue: 0.22), - gradientBottom: Color(red: 0.05, green: 0.10, blue: 0.08) + id: "morning-focus", name: "Morning Focus", + startMinutes: 8 * 60, endMinutes: 11 * 60 + 30, days: Weekday.weekdays, + symbolName: "sunrise.fill", + gradientTop: Color(red: 0.33, green: 0.23, blue: 0.13), + gradientBottom: Color(red: 0.12, green: 0.07, blue: 0.03) ), RulePreset( - id: "laser-focus", name: "Laser Focus", - startMinutes: 14 * 60, endMinutes: 18 * 60, days: Weekday.weekdays, + id: "deep-work", name: "Deep Work", + startMinutes: 13 * 60 + 30, endMinutes: 16 * 60, days: Weekday.weekdays, symbolName: "scope", gradientTop: Color(red: 0.13, green: 0.20, blue: 0.33), gradientBottom: Color(red: 0.04, green: 0.06, blue: 0.12) @@ -52,20 +52,20 @@ struct RulePresetSection: Identifiable, Hashable, Sendable { ] ), RulePresetSection( - id: "sleep", - title: "Sleep, Relax and Reset", - subtitle: "Sleep better, rise refreshed.", + id: "rest", + title: "Rest & Recharge", + subtitle: "Wind the day down on schedule.", presets: [ RulePreset( - id: "wind-down", name: "Wind Down", - startMinutes: 20 * 60, endMinutes: 22 * 60, days: Weekday.everyDay, + id: "evening-reset", name: "Evening Reset", + startMinutes: 21 * 60, endMinutes: 23 * 60, days: Weekday.everyDay, symbolName: "moon.haze.fill", gradientTop: Color(red: 0.25, green: 0.18, blue: 0.33), gradientBottom: Color(red: 0.08, green: 0.05, blue: 0.12) ), RulePreset( - id: "deep-sleep", name: "Deep Sleep", - startMinutes: 22 * 60, endMinutes: 6 * 60, days: Weekday.everyDay, + id: "lights-out", name: "Lights Out", + startMinutes: 23 * 60, endMinutes: 6 * 60 + 30, days: Weekday.everyDay, symbolName: "moon.zzz.fill", gradientTop: Color(red: 0.10, green: 0.13, blue: 0.30), gradientBottom: Color(red: 0.02, green: 0.03, blue: 0.10) @@ -73,21 +73,21 @@ struct RulePresetSection: Identifiable, Hashable, Sendable { ] ), RulePresetSection( - id: "habits", - title: "Build Healthy Habits", - subtitle: "Spend time on important things.", + id: "balance", + title: "Healthy Balance", + subtitle: "Make room for what matters.", presets: [ RulePreset( - id: "reading-time", name: "Reading Time", - startMinutes: 19 * 60 + 45, endMinutes: 20 * 60 + 45, days: Weekday.everyDay, - symbolName: "book.fill", - gradientTop: Color(red: 0.33, green: 0.23, blue: 0.13), - gradientBottom: Color(red: 0.12, green: 0.07, blue: 0.03) + id: "family-dinner", name: "Family Dinner", + startMinutes: 18 * 60, endMinutes: 19 * 60 + 30, days: Weekday.everyDay, + symbolName: "fork.knife", + gradientTop: Color(red: 0.16, green: 0.27, blue: 0.22), + gradientBottom: Color(red: 0.05, green: 0.10, blue: 0.08) ), RulePreset( - id: "gym-time", name: "Gym Time", - startMinutes: 17 * 60 + 30, endMinutes: 18 * 60 + 30, days: Weekday.everyDay, - symbolName: "figure.run", + id: "screen-free-sunday", name: "Screen-Free Sunday", + startMinutes: 9 * 60, endMinutes: 20 * 60, days: [.sunday], + symbolName: "leaf.fill", gradientTop: Color(red: 0.13, green: 0.30, blue: 0.30), gradientBottom: Color(red: 0.03, green: 0.10, blue: 0.10) ), diff --git a/OpenAppLockTests/RuleModelTests.swift b/OpenAppLockTests/RuleModelTests.swift index e6f5162..7a70f38 100644 --- a/OpenAppLockTests/RuleModelTests.swift +++ b/OpenAppLockTests/RuleModelTests.swift @@ -177,12 +177,12 @@ struct RuleDraftTests { let preset = try #require( RulePresetSection.all .flatMap(\.presets) - .first { $0.id == "deep-sleep" } + .first { $0.id == "lights-out" } ) let draft = RuleDraft(preset: preset) - #expect(draft.name == "Deep Sleep") - #expect(draft.scheduleConfig.startMinutes == 22 * 60) - #expect(draft.scheduleConfig.endMinutes == 6 * 60) + #expect(draft.name == "Lights Out") + #expect(draft.scheduleConfig.startMinutes == 23 * 60) + #expect(draft.scheduleConfig.endMinutes == 6 * 60 + 30) #expect(draft.kind == .schedule) } } diff --git a/OpenAppLockUITests/RuleCreationUITests.swift b/OpenAppLockUITests/RuleCreationUITests.swift index d121f22..caf8586 100644 --- a/OpenAppLockUITests/RuleCreationUITests.swift +++ b/OpenAppLockUITests/RuleCreationUITests.swift @@ -37,11 +37,11 @@ final class RuleCreationUITests: XCTestCase { app.goToRulesTab() app.buttons["newRuleButton"].waitToAppear().tap() - app.buttons["preset-work-time"].waitToAppear().tap() - XCTAssertEqual(app.staticTexts["ruleEditorTitle"].waitToAppear().label, "Work Time") + app.buttons["preset-morning-focus"].waitToAppear().tap() + XCTAssertEqual(app.staticTexts["ruleEditorTitle"].waitToAppear().label, "Morning Focus") app.buttons["commitRuleButton"].waitToAppear().tap() - app.buttons["ruleCard-Work Time"].waitToAppear() + app.buttons["ruleCard-Morning Focus"].waitToAppear() } func testRenameRuleInEditor() throws { @@ -190,8 +190,8 @@ final class RuleCreationUITests: XCTestCase { app.buttons["ruleKind-schedule"].waitToAppear() XCTAssertTrue(app.buttons["ruleKind-timeLimit"].exists) XCTAssertTrue(app.buttons["ruleKind-openLimit"].exists) - XCTAssertTrue(app.staticTexts["Get More Done"].exists) - XCTAssertTrue(app.buttons["preset-work-time"].exists) - XCTAssertTrue(app.buttons["preset-laser-focus"].exists) + XCTAssertTrue(app.staticTexts["Focus Time"].exists) + XCTAssertTrue(app.buttons["preset-morning-focus"].exists) + XCTAssertTrue(app.buttons["preset-deep-work"].exists) } } diff --git a/docs/RULES_FEATURE_SPEC.md b/docs/RULES_FEATURE_SPEC.md index ec300b6..ead2d9b 100644 --- a/docs/RULES_FEATURE_SPEC.md +++ b/docs/RULES_FEATURE_SPEC.md @@ -20,7 +20,7 @@ offered, presented on the "New Rule" sheet: **Common attributes** — present for *every* rule kind: -- **Name** — user-editable, free text (presets: "Work Time", "Weekend Zen", "Locked In", "Sleep", "Wind Down", "Deep Sleep", "Laser Focus", "Reading Time", "Gym Time"; defaults for new rules: "In the Zone" (schedule), "Time Keeper" (time limit)) +- **Name** — user-editable, free text (presets: "Morning Focus", "Deep Work", "Evening Reset", "Lights Out", "Family Dinner", "Screen-Free Sunday"; defaults for new rules: "In the Zone" (schedule), "Time Keeper" (time limit)) - **Days of week** — 7-day toggle set, summarized as "Weekdays" / "Weekends" / "Every day" / custom - **App List** *(OpenAppLock refinement)* — each rule points to exactly one **App List**: a named, reusable selection of apps/categories/websites stored @@ -145,15 +145,15 @@ Presented from "+ New". Full-height sheet, scrollable. defaults. - **Preset gallery** — vertically scrolling sections, each with a bold header + grey subtitle, containing a 2-up grid of photo-backed preset cards: - - **Get More Done** — "Maximize your productivity while staying sane." - - Work Time (Schedule 09:00–17:00, Block, weekdays) - - Laser Focus (Schedule 14:00–18:00, Block) - - **Sleep, Relax and Reset** — "Sleep better, rise refreshed." - - Wind Down (Schedule 20:00–22:00, Block) - - Deep Sleep (Schedule 22:00–06:00, Block) - - **Build Healthy Habits** — "Spend time on important things." - - Reading Time (Schedule ~19:45–20:45, Block) - - Gym Time (Schedule 17:30–18:30, Block) + - **Focus Time** — "Protect your deep-work hours." + - Morning Focus (Schedule 08:00–11:30, Block, weekdays) + - Deep Work (Schedule 13:30–16:00, Block, weekdays) + - **Rest & Recharge** — "Wind the day down on schedule." + - Evening Reset (Schedule 21:00–23:00, Block) + - Lights Out (Schedule 23:00–06:30, Block) + - **Healthy Balance** — "Make room for what matters." + - Family Dinner (Schedule 18:00–19:30, Block) + - Screen-Free Sunday (Schedule 09:00–20:00, Block, Sundays) - **Preset card** anatomy: full-bleed background photo, top row icon pair (type → shield), time range caption, name, "Block" + suggested app icons, and a circular "+" button bottom-right. Tapping anywhere opens the @@ -266,8 +266,8 @@ Full-height sheet: ## 4. Behavioral spec 1. **Activation** — a Schedule rule becomes active at `From` on an enabled - day and deactivates at `To` (windows crossing midnight, e.g. 22:00–06:00, - must be supported — Deep Sleep preset does this). + day and deactivates at `To` (windows crossing midnight, e.g. 23:00–06:30, + must be supported — Lights Out preset does this). 2. **While active** — the rule's app selection is shielded (and, when the rule's Block Adult Content toggle is on, Screen Time's adult-website filter is engaged for the same span); blocked apps also