feat: re-skin to native three-tab UI and add Uninstall Protection

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>
This commit is contained in:
2026-06-13 22:17:08 -04:00
parent 0a0d00f53a
commit 32b1694e0a
26 changed files with 1039 additions and 427 deletions

View File

@@ -17,15 +17,17 @@ final class OnboardingUITests: XCTestCase {
app.staticTexts["OpenAppLock"].waitToAppear()
app.buttons["onboardingContinueButton"].waitToAppear().tap()
// Permission step: granting (mocked) lands on the Apps home screen.
// Permission step: granting (mocked) lands on the tabbed home screen.
app.buttons["allowScreenTimeButton"].waitToAppear().tap()
app.buttons["newRuleButton"].waitToAppear()
XCTAssertTrue(app.staticTexts["Blocked Apps"].exists)
app.tabBars.buttons["Home"].waitToAppear()
XCTAssertTrue(app.tabBars.buttons["Rules"].exists)
XCTAssertTrue(app.tabBars.buttons["Settings"].exists)
XCTAssertTrue(app.staticTexts["Currently Blocking"].exists)
}
func testCompletedOnboardingIsSkipped() throws {
let app = XCUIApplication.launchOpenAppLock(onboardingCompleted: true)
app.buttons["newRuleButton"].waitToAppear()
app.tabBars.buttons["Home"].waitToAppear()
XCTAssertFalse(app.buttons["onboardingContinueButton"].exists)
}
}