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:
@@ -6,7 +6,8 @@
|
||||
import XCTest
|
||||
|
||||
/// App lists: the editor's App List row, the picker (select / create / edit),
|
||||
/// rule-level Block vs Allow Only, and the Hard Mode list lockdown.
|
||||
/// rule-level Block vs Allow Only, and the Hard Mode list lockdown. The rule
|
||||
/// editor (and its app-list picker) is reached from the Rules tab.
|
||||
final class AppListUITests: XCTestCase {
|
||||
override func setUpWithError() throws {
|
||||
continueAfterFailure = false
|
||||
@@ -14,6 +15,7 @@ final class AppListUITests: XCTestCase {
|
||||
|
||||
func testScheduleEditorOffersModeChoice() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock()
|
||||
app.goToRulesTab()
|
||||
app.buttons["newRuleButton"].waitToAppear().tap()
|
||||
app.buttons["ruleKind-schedule"].waitToAppear().tap()
|
||||
|
||||
@@ -25,6 +27,7 @@ final class AppListUITests: XCTestCase {
|
||||
|
||||
func testLimitEditorsAreBlockOnly() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock()
|
||||
app.goToRulesTab()
|
||||
app.buttons["newRuleButton"].waitToAppear().tap()
|
||||
|
||||
app.buttons["ruleKind-timeLimit"].waitToAppear().tap()
|
||||
@@ -46,6 +49,7 @@ final class AppListUITests: XCTestCase {
|
||||
|
||||
func testCreateAppListFlowSelectsNewList() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock()
|
||||
app.goToRulesTab()
|
||||
app.buttons["newRuleButton"].waitToAppear().tap()
|
||||
app.buttons["ruleKind-timeLimit"].waitToAppear().tap()
|
||||
|
||||
@@ -79,6 +83,7 @@ final class AppListUITests: XCTestCase {
|
||||
|
||||
func testDetailShowsAppListName() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock(seedScenario: "standard")
|
||||
app.goToRulesTab()
|
||||
app.buttons["ruleCard-Work Time"].waitToAppear().tap()
|
||||
|
||||
let row = app.element("detailRow-Block").waitToAppear()
|
||||
@@ -87,6 +92,7 @@ final class AppListUITests: XCTestCase {
|
||||
|
||||
func testHardModeSessionLocksAppListEditing() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock(seedScenario: "hard-mode-active")
|
||||
app.goToRulesTab()
|
||||
|
||||
// "Sleep" is soft and editable even while "Locked In" hard-blocks.
|
||||
app.buttons["ruleCard-Sleep"].waitToAppear().tap()
|
||||
@@ -103,6 +109,7 @@ final class AppListUITests: XCTestCase {
|
||||
|
||||
func testAppListsEditableWithoutHardSession() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock(seedScenario: "standard")
|
||||
app.goToRulesTab()
|
||||
|
||||
app.buttons["ruleCard-Sleep"].waitToAppear().tap()
|
||||
app.buttons["editRuleButton"].waitToAppear().tap()
|
||||
|
||||
Reference in New Issue
Block a user