Replace the custom themed presentation with the bare native iOS design
language across a three-tab TabView (Home / Rules / Settings):
- MainTabView hosts the enforcement lifecycle (refresh loop, rule-change
and scene-active reconcile) so it runs regardless of the selected tab
- HomeView: "Currently Blocking" + "Usage" sections (replaces AppsHomeView)
- RulesListView: rules grouped into Schedule / Time Limit / Open Limit
- SettingsView: Uninstall Protection toggle + Manage App Lists
- AppListLibraryView / ManageAppListsView: shared App List management
- AppSettings: app-group-backed settings store
Uninstall Protection: while enabled and any Hard Mode rule is actively
blocking, deny device app-removal via a dedicated ManagedSettingsStore
(RulePolicy.shouldDenyAppRemoval -> RuleEnforcer -> ShieldController).
Slim AppListPickerSheet to the picker role; drop AppsHomeView and the
custom Theme/HoldToCommitButton/RuleCardView chrome. Update spec section 6
and the unit/UI test suites accordingly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 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>