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.
This commit is contained in:
@@ -12,6 +12,7 @@ final class RuleCreationUITests: XCTestCase {
|
||||
|
||||
func testCreateScheduleRuleFromTypeCard() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock()
|
||||
app.goToRulesTab()
|
||||
app.element("emptyRulesCard").waitToAppear()
|
||||
|
||||
app.buttons["newRuleButton"].tap()
|
||||
@@ -33,6 +34,7 @@ final class RuleCreationUITests: XCTestCase {
|
||||
|
||||
func testCreateRuleFromPreset() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock()
|
||||
app.goToRulesTab()
|
||||
app.buttons["newRuleButton"].waitToAppear().tap()
|
||||
|
||||
app.buttons["preset-work-time"].waitToAppear().tap()
|
||||
@@ -44,6 +46,7 @@ final class RuleCreationUITests: XCTestCase {
|
||||
|
||||
func testRenameRuleInEditor() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock()
|
||||
app.goToRulesTab()
|
||||
app.buttons["newRuleButton"].waitToAppear().tap()
|
||||
app.buttons["ruleKind-schedule"].waitToAppear().tap()
|
||||
|
||||
@@ -63,6 +66,7 @@ final class RuleCreationUITests: XCTestCase {
|
||||
|
||||
func testDayTogglesFillRowAndHaveLargeTapTargets() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock()
|
||||
app.goToRulesTab()
|
||||
app.buttons["newRuleButton"].waitToAppear().tap()
|
||||
app.buttons["ruleKind-schedule"].waitToAppear().tap()
|
||||
|
||||
@@ -81,6 +85,7 @@ final class RuleCreationUITests: XCTestCase {
|
||||
|
||||
func testDayTogglesUpdateSummary() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock()
|
||||
app.goToRulesTab()
|
||||
app.buttons["newRuleButton"].waitToAppear().tap()
|
||||
app.buttons["ruleKind-schedule"].waitToAppear().tap()
|
||||
|
||||
@@ -93,6 +98,7 @@ final class RuleCreationUITests: XCTestCase {
|
||||
|
||||
func testCreateTimeLimitRule() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock()
|
||||
app.goToRulesTab()
|
||||
app.buttons["newRuleButton"].waitToAppear().tap()
|
||||
app.buttons["ruleKind-timeLimit"].waitToAppear().tap()
|
||||
|
||||
@@ -109,6 +115,7 @@ final class RuleCreationUITests: XCTestCase {
|
||||
|
||||
func testAdultContentToggleFlowsToDetail() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock()
|
||||
app.goToRulesTab()
|
||||
app.buttons["newRuleButton"].waitToAppear().tap()
|
||||
app.buttons["ruleKind-schedule"].waitToAppear().tap()
|
||||
|
||||
@@ -126,6 +133,7 @@ final class RuleCreationUITests: XCTestCase {
|
||||
|
||||
func testAdultContentDefaultsToAllowed() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock(seedScenario: "standard")
|
||||
app.goToRulesTab()
|
||||
app.buttons["ruleCard-Work Time"].waitToAppear().tap()
|
||||
let row = app.element("detailRow-Adult websites").waitToAppear()
|
||||
XCTAssertTrue(row.label.contains("Allowed"), "Got: \(row.label)")
|
||||
@@ -135,6 +143,7 @@ final class RuleCreationUITests: XCTestCase {
|
||||
/// not offer the toggle, and the rule's detail must not show the row.
|
||||
func testTimeLimitOmitsAdultContent() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock()
|
||||
app.goToRulesTab()
|
||||
app.buttons["newRuleButton"].waitToAppear().tap()
|
||||
app.buttons["ruleKind-timeLimit"].waitToAppear().tap()
|
||||
|
||||
@@ -159,6 +168,7 @@ final class RuleCreationUITests: XCTestCase {
|
||||
|
||||
func testEditorSupportsNativeSwipeBack() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock()
|
||||
app.goToRulesTab()
|
||||
app.buttons["newRuleButton"].waitToAppear().tap()
|
||||
app.buttons["ruleKind-schedule"].waitToAppear().tap()
|
||||
app.staticTexts["ruleEditorTitle"].waitToAppear()
|
||||
@@ -174,6 +184,7 @@ final class RuleCreationUITests: XCTestCase {
|
||||
|
||||
func testNewRuleSheetShowsTypesAndPresets() throws {
|
||||
let app = XCUIApplication.launchOpenAppLock()
|
||||
app.goToRulesTab()
|
||||
app.buttons["newRuleButton"].waitToAppear().tap()
|
||||
|
||||
app.buttons["ruleKind-schedule"].waitToAppear()
|
||||
|
||||
Reference in New Issue
Block a user