feat: introduce reusable app lists for rules
- AppList @Model with launch migration from legacy inline selections (rules with identical selections share one list; idempotent) - rules point at one app list; Block/Allow Only belongs to the rule and is offered only in the Schedule editor (limit kinds sanitize to Block) - app-list picker sheet (select / create / edit / delete with in-use protection) replaces the per-rule selection sheet - Hard Mode locks app-list editing while any hard rule is blocking - SwiftData stability: relationships are only wired between managed models, and unit tests share one in-memory container (fresh context + data wipe per test) — per-test container creation trapped intermittently inside SwiftData
This commit is contained in:
@@ -23,7 +23,16 @@ Common attributes across all types:
|
||||
|
||||
- **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))
|
||||
- **Days of week** — 7-day toggle set, summarized as "Weekdays" / "Weekends" / "Every day" / custom
|
||||
- **App selection** — apps, categories, and websites; selection mode is either **Block** (block selected) or **Allow Only** (block everything except selected)
|
||||
- **App List** *(OpenAppLock refinement)* — each rule points to exactly one
|
||||
**App List**: a named, reusable selection of apps/categories/websites stored
|
||||
independently of any rule. When editing a rule the user picks an existing
|
||||
list or creates a new one; editing a list affects every rule that uses it.
|
||||
Deleting a list detaches it from its rules (they fall back to "no apps").
|
||||
- **Selection mode** — **Block** (block the list) or **Allow Only** (block
|
||||
everything except the list). The mode belongs to the *rule*, not the list.
|
||||
Only **Schedule** rules offer the choice; Time Limit and Open Limit rules
|
||||
are always Block (a usage budget over "everything except X" is not
|
||||
meaningful, and drafts of those kinds are sanitized back to Block).
|
||||
- **Hard Mode** — boolean, PRO-gated in Opal; subtitle "No unblocks allowed". When off, the rule detail shows "Unblocks allowed: Yes"
|
||||
- **Enabled/disabled** — a rule can be disabled without deleting ("Disable Rule")
|
||||
|
||||
@@ -147,7 +156,11 @@ Sections (each an inset rounded group with a small icon + caption header):
|
||||
row of 7 circular toggles `S M T W T F S`; selected = filled white circle
|
||||
with black letter, unselected = dark circle.
|
||||
3. **🛡 Apps are blocked**
|
||||
- Row: `Selected Apps` → `N Apps ›` — pushes the App Picker.
|
||||
- Row: `App List` → `<list name> · N Apps ›` (or `Choose ›` when none) —
|
||||
presents the App List picker.
|
||||
- A segmented `Block | Allow Only` row (Schedule editor only) chooses how
|
||||
the rule interprets its list; the section header reads "Apps are
|
||||
blocked" / "Only these apps are allowed" accordingly.
|
||||
4. **Hard Mode** `⚡PRO` badge — subtitle "No unblocks allowed"; trailing
|
||||
toggle.
|
||||
5. **Block Adult Content** *(OpenAppLock addition — not in the Opal video)* —
|
||||
@@ -209,8 +222,22 @@ Full-height sheet:
|
||||
> parties cannot enumerate installed apps; the system-sanctioned route is
|
||||
> `FamilyActivityPicker` (FamilyControls), which provides its own
|
||||
> category/app/website UI and returns opaque tokens. **v1 of OpenAppLock should
|
||||
> embed `FamilyActivityPicker`** instead of cloning Opal's custom picker, and
|
||||
> keep the `Block`/`Allow Only` segmented control as our own wrapper state.
|
||||
> embed `FamilyActivityPicker`** instead of cloning Opal's custom picker.
|
||||
>
|
||||
> **App Lists (OpenAppLock):** the selection itself lives on a reusable
|
||||
> **App List** (`@Model AppList`: name + encoded `FamilyActivitySelection`).
|
||||
> The editor's App List row presents a picker sheet listing saved lists
|
||||
> (checkmark on the rule's current list; tap to select), an Edit affordance
|
||||
> per list, and a "New List" flow — a name field plus an embedded
|
||||
> `FamilyActivityPicker`. The `Block`/`Allow Only` segmented control lives in
|
||||
> the Schedule rule editor (it is rule state, not list state). Legacy rules
|
||||
> that stored an inline selection are migrated at launch: one list per
|
||||
> distinct selection (rules sharing identical selection data share a list),
|
||||
> named "<rule name> Apps". Lists in use by a rule cannot be deleted from the
|
||||
> picker. While any **Hard Mode** rule is actively blocking, all lists are
|
||||
> read-only — the picker hides Edit/Delete and shows a lock notice — because
|
||||
> editing a list would be a back door out of the hard block. Creating new
|
||||
> lists and selecting lists for other rules remain available.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user