diff --git a/AGENTS.md b/AGENTS.md index 2031051..d441d2e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ -# Severed — Agent Guide +# OpenAppLock — Agent Guide -Severed is an iOS Screen Time app: recurring **rules** that block selected +OpenAppLock is an iOS Screen Time app: recurring **rules** that block selected apps (Schedule windows, Time Limits, Open Limits), with a **Hard Mode** that makes an active block impossible to lift, edit, or delete until it ends. The feature set is a clone of Opal's "Rules"; the presentation is bare native iOS @@ -9,7 +9,7 @@ feature set is a clone of Opal's "Rules"; the presentation is bare native iOS ## Repo layout ``` -Severed/ App target (iOS 26, SwiftUI + SwiftData) +OpenAppLock/ App target (iOS 26, SwiftUI + SwiftData) Models/ BlockingRule (@Model), RuleDraft, RuleKind, Weekday, RulePreset Logic/ Pure, heavily unit-tested: @@ -22,9 +22,9 @@ Severed/ App target (iOS 26, SwiftUI + SwiftData) RuleEnforcer (active rules → shields), LaunchConfiguration + SampleRules (UI-test harness) Views/ Native SwiftUI screens (see docs spec §6) -SeveredTests/ Swift Testing unit suites (@MainActor — the app +OpenAppLockTests/ Swift Testing unit suites (@MainActor — the app target defaults to MainActor isolation) -SeveredUITests/ XCUITest flows (see harness below) +OpenAppLockUITests/ XCUITest flows (see harness below) docs/RULES_FEATURE_SPEC.md Feature spec derived from the Opal reference recording; §6 maps it to the native presentation. Review/update this BEFORE behavior changes. @@ -50,14 +50,14 @@ docs/RULES_FEATURE_SPEC.md Feature spec derived from the Opal reference ## Build & test -- Open `Severed.xcodeproj` in Xcode; build/test through the **Xcode MCP** +- Open `OpenAppLock.xcodeproj` in Xcode; build/test through the **Xcode MCP** tools (`BuildProject`, `RunAllTests`, `RunSomeTests` — get the tab id from `XcodeListWindows`). Make sure the scheme destination is an iOS **simulator**; a physical-device destination makes test runs hang or get cancelled. - The project uses Xcode file-system-synchronized groups: adding/removing `.swift` files on disk is enough, no pbxproj editing. -- Family Controls entitlement is configured (`Severed/Severed.entitlements`). +- Family Controls entitlement is configured (`OpenAppLock/OpenAppLock.entitlements`). FamilyControls/ManagedSettings compile and run on the simulator, but real blocking behavior is only observable on a device. @@ -72,7 +72,7 @@ docs/RULES_FEATURE_SPEC.md Feature spec derived from the Opal reference ## UI-test harness -`SeveredApp` reads launch arguments (parsed by `LaunchConfiguration`): +`OpenAppLockApp` reads launch arguments (parsed by `LaunchConfiguration`): | Argument | Effect | |---|---| @@ -81,7 +81,7 @@ docs/RULES_FEATURE_SPEC.md Feature spec derived from the Opal reference | `-seed-scenario=standard` | Active soft rule "Work Time" + upcoming "Sleep" | | `-seed-scenario=hard-mode-active` | Active Hard Mode rule "Locked In" + upcoming "Sleep" | -Use `XCUIApplication.launchSevered(...)` (UITestSupport.swift), which also +Use `XCUIApplication.launchOpenAppLock(...)` (UITestSupport.swift), which also provides `app.element(_:)` for identifier lookup across element types and `waitToAppear()`. diff --git a/CLAUDE.md b/CLAUDE.md index 393ef38..efa9431 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,4 +1,4 @@ -# Severed +# OpenAppLock All project context for agents lives in [AGENTS.md](AGENTS.md) — read that first. Feature behavior is specified in diff --git a/Severed.xcodeproj/project.pbxproj b/OpenAppLock.xcodeproj/project.pbxproj similarity index 85% rename from Severed.xcodeproj/project.pbxproj rename to OpenAppLock.xcodeproj/project.pbxproj index 7fb224d..477e898 100644 --- a/Severed.xcodeproj/project.pbxproj +++ b/OpenAppLock.xcodeproj/project.pbxproj @@ -12,37 +12,37 @@ containerPortal = 20A7EDC62E47B7CD0097608D /* Project object */; proxyType = 1; remoteGlobalIDString = 20A7EDCD2E47B7CD0097608D; - remoteInfo = Severed; + remoteInfo = OpenAppLock; }; 20A7EDE82E47B7CF0097608D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 20A7EDC62E47B7CD0097608D /* Project object */; proxyType = 1; remoteGlobalIDString = 20A7EDCD2E47B7CD0097608D; - remoteInfo = Severed; + remoteInfo = OpenAppLock; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 20A7EDCE2E47B7CD0097608D /* Severed.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Severed.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 20A7EDDD2E47B7CF0097608D /* SeveredTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SeveredTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 20A7EDE72E47B7CF0097608D /* SeveredUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SeveredUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 20A7EDCE2E47B7CD0097608D /* OpenAppLock.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OpenAppLock.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 20A7EDDD2E47B7CF0097608D /* OpenAppLockTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OpenAppLockTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 20A7EDE72E47B7CF0097608D /* OpenAppLockUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OpenAppLockUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ - 20A7EDD02E47B7CD0097608D /* Severed */ = { + 20A7EDD02E47B7CD0097608D /* OpenAppLock */ = { isa = PBXFileSystemSynchronizedRootGroup; - path = Severed; + path = OpenAppLock; sourceTree = ""; }; - 20A7EDE02E47B7CF0097608D /* SeveredTests */ = { + 20A7EDE02E47B7CF0097608D /* OpenAppLockTests */ = { isa = PBXFileSystemSynchronizedRootGroup; - path = SeveredTests; + path = OpenAppLockTests; sourceTree = ""; }; - 20A7EDEA2E47B7CF0097608D /* SeveredUITests */ = { + 20A7EDEA2E47B7CF0097608D /* OpenAppLockUITests */ = { isa = PBXFileSystemSynchronizedRootGroup; - path = SeveredUITests; + path = OpenAppLockUITests; sourceTree = ""; }; /* End PBXFileSystemSynchronizedRootGroup section */ @@ -75,9 +75,9 @@ 20A7EDC52E47B7CD0097608D = { isa = PBXGroup; children = ( - 20A7EDD02E47B7CD0097608D /* Severed */, - 20A7EDE02E47B7CF0097608D /* SeveredTests */, - 20A7EDEA2E47B7CF0097608D /* SeveredUITests */, + 20A7EDD02E47B7CD0097608D /* OpenAppLock */, + 20A7EDE02E47B7CF0097608D /* OpenAppLockTests */, + 20A7EDEA2E47B7CF0097608D /* OpenAppLockUITests */, 20A7EDCF2E47B7CD0097608D /* Products */, ); sourceTree = ""; @@ -85,9 +85,9 @@ 20A7EDCF2E47B7CD0097608D /* Products */ = { isa = PBXGroup; children = ( - 20A7EDCE2E47B7CD0097608D /* Severed.app */, - 20A7EDDD2E47B7CF0097608D /* SeveredTests.xctest */, - 20A7EDE72E47B7CF0097608D /* SeveredUITests.xctest */, + 20A7EDCE2E47B7CD0097608D /* OpenAppLock.app */, + 20A7EDDD2E47B7CF0097608D /* OpenAppLockTests.xctest */, + 20A7EDE72E47B7CF0097608D /* OpenAppLockUITests.xctest */, ); name = Products; sourceTree = ""; @@ -95,9 +95,9 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 20A7EDCD2E47B7CD0097608D /* Severed */ = { + 20A7EDCD2E47B7CD0097608D /* OpenAppLock */ = { isa = PBXNativeTarget; - buildConfigurationList = 20A7EDF12E47B7CF0097608D /* Build configuration list for PBXNativeTarget "Severed" */; + buildConfigurationList = 20A7EDF12E47B7CF0097608D /* Build configuration list for PBXNativeTarget "OpenAppLock" */; buildPhases = ( 20A7EDCA2E47B7CD0097608D /* Sources */, 20A7EDCB2E47B7CD0097608D /* Frameworks */, @@ -108,18 +108,18 @@ dependencies = ( ); fileSystemSynchronizedGroups = ( - 20A7EDD02E47B7CD0097608D /* Severed */, + 20A7EDD02E47B7CD0097608D /* OpenAppLock */, ); - name = Severed; + name = OpenAppLock; packageProductDependencies = ( ); - productName = Severed; - productReference = 20A7EDCE2E47B7CD0097608D /* Severed.app */; + productName = OpenAppLock; + productReference = 20A7EDCE2E47B7CD0097608D /* OpenAppLock.app */; productType = "com.apple.product-type.application"; }; - 20A7EDDC2E47B7CF0097608D /* SeveredTests */ = { + 20A7EDDC2E47B7CF0097608D /* OpenAppLockTests */ = { isa = PBXNativeTarget; - buildConfigurationList = 20A7EDF42E47B7CF0097608D /* Build configuration list for PBXNativeTarget "SeveredTests" */; + buildConfigurationList = 20A7EDF42E47B7CF0097608D /* Build configuration list for PBXNativeTarget "OpenAppLockTests" */; buildPhases = ( 20A7EDD92E47B7CF0097608D /* Sources */, 20A7EDDA2E47B7CF0097608D /* Frameworks */, @@ -131,18 +131,18 @@ 20A7EDDF2E47B7CF0097608D /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( - 20A7EDE02E47B7CF0097608D /* SeveredTests */, + 20A7EDE02E47B7CF0097608D /* OpenAppLockTests */, ); - name = SeveredTests; + name = OpenAppLockTests; packageProductDependencies = ( ); - productName = SeveredTests; - productReference = 20A7EDDD2E47B7CF0097608D /* SeveredTests.xctest */; + productName = OpenAppLockTests; + productReference = 20A7EDDD2E47B7CF0097608D /* OpenAppLockTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; - 20A7EDE62E47B7CF0097608D /* SeveredUITests */ = { + 20A7EDE62E47B7CF0097608D /* OpenAppLockUITests */ = { isa = PBXNativeTarget; - buildConfigurationList = 20A7EDF72E47B7CF0097608D /* Build configuration list for PBXNativeTarget "SeveredUITests" */; + buildConfigurationList = 20A7EDF72E47B7CF0097608D /* Build configuration list for PBXNativeTarget "OpenAppLockUITests" */; buildPhases = ( 20A7EDE32E47B7CF0097608D /* Sources */, 20A7EDE42E47B7CF0097608D /* Frameworks */, @@ -154,13 +154,13 @@ 20A7EDE92E47B7CF0097608D /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( - 20A7EDEA2E47B7CF0097608D /* SeveredUITests */, + 20A7EDEA2E47B7CF0097608D /* OpenAppLockUITests */, ); - name = SeveredUITests; + name = OpenAppLockUITests; packageProductDependencies = ( ); - productName = SeveredUITests; - productReference = 20A7EDE72E47B7CF0097608D /* SeveredUITests.xctest */; + productName = OpenAppLockUITests; + productReference = 20A7EDE72E47B7CF0097608D /* OpenAppLockUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; }; /* End PBXNativeTarget section */ @@ -186,7 +186,7 @@ }; }; }; - buildConfigurationList = 20A7EDC92E47B7CD0097608D /* Build configuration list for PBXProject "Severed" */; + buildConfigurationList = 20A7EDC92E47B7CD0097608D /* Build configuration list for PBXProject "OpenAppLock" */; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -200,9 +200,9 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 20A7EDCD2E47B7CD0097608D /* Severed */, - 20A7EDDC2E47B7CF0097608D /* SeveredTests */, - 20A7EDE62E47B7CF0097608D /* SeveredUITests */, + 20A7EDCD2E47B7CD0097608D /* OpenAppLock */, + 20A7EDDC2E47B7CF0097608D /* OpenAppLockTests */, + 20A7EDE62E47B7CF0097608D /* OpenAppLockUITests */, ); }; /* End PBXProject section */ @@ -258,12 +258,12 @@ /* Begin PBXTargetDependency section */ 20A7EDDF2E47B7CF0097608D /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 20A7EDCD2E47B7CD0097608D /* Severed */; + target = 20A7EDCD2E47B7CD0097608D /* OpenAppLock */; targetProxy = 20A7EDDE2E47B7CF0097608D /* PBXContainerItemProxy */; }; 20A7EDE92E47B7CF0097608D /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 20A7EDCD2E47B7CD0097608D /* Severed */; + target = 20A7EDCD2E47B7CD0097608D /* OpenAppLock */; targetProxy = 20A7EDE82E47B7CF0097608D /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -390,7 +390,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = Severed/Severed.entitlements; + CODE_SIGN_ENTITLEMENTS = OpenAppLock/OpenAppLock.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 4A9XHUS87Q; @@ -414,7 +414,7 @@ "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 15.6; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.bchen.Severed; + PRODUCT_BUNDLE_IDENTIFIER = dev.bchen.OpenAppLock; PRODUCT_NAME = "$(TARGET_NAME)"; REGISTER_APP_GROUPS = YES; SDKROOT = auto; @@ -433,7 +433,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = Severed/Severed.entitlements; + CODE_SIGN_ENTITLEMENTS = OpenAppLock/OpenAppLock.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 4A9XHUS87Q; @@ -457,7 +457,7 @@ "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 15.6; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.bchen.Severed; + PRODUCT_BUNDLE_IDENTIFIER = dev.bchen.OpenAppLock; PRODUCT_NAME = "$(TARGET_NAME)"; REGISTER_APP_GROUPS = YES; SDKROOT = auto; @@ -482,7 +482,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 26.0; MACOSX_DEPLOYMENT_TARGET = 15.6; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.bchen.SeveredTests; + PRODUCT_BUNDLE_IDENTIFIER = dev.bchen.OpenAppLockTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; STRING_CATALOG_GENERATE_SYMBOLS = NO; @@ -491,7 +491,7 @@ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Severed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Severed"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/OpenAppLock.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/OpenAppLock"; XROS_DEPLOYMENT_TARGET = 26.0; }; name = Debug; @@ -507,7 +507,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 26.0; MACOSX_DEPLOYMENT_TARGET = 15.6; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.bchen.SeveredTests; + PRODUCT_BUNDLE_IDENTIFIER = dev.bchen.OpenAppLockTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; STRING_CATALOG_GENERATE_SYMBOLS = NO; @@ -516,7 +516,7 @@ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Severed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Severed"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/OpenAppLock.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/OpenAppLock"; XROS_DEPLOYMENT_TARGET = 26.0; }; name = Release; @@ -531,7 +531,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 26.0; MACOSX_DEPLOYMENT_TARGET = 15.6; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.bchen.SeveredUITests; + PRODUCT_BUNDLE_IDENTIFIER = dev.bchen.OpenAppLockUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; STRING_CATALOG_GENERATE_SYMBOLS = NO; @@ -540,7 +540,7 @@ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - TEST_TARGET_NAME = Severed; + TEST_TARGET_NAME = OpenAppLock; XROS_DEPLOYMENT_TARGET = 26.0; }; name = Debug; @@ -555,7 +555,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 26.0; MACOSX_DEPLOYMENT_TARGET = 15.6; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.bchen.SeveredUITests; + PRODUCT_BUNDLE_IDENTIFIER = dev.bchen.OpenAppLockUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; STRING_CATALOG_GENERATE_SYMBOLS = NO; @@ -564,7 +564,7 @@ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - TEST_TARGET_NAME = Severed; + TEST_TARGET_NAME = OpenAppLock; XROS_DEPLOYMENT_TARGET = 26.0; }; name = Release; @@ -572,7 +572,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 20A7EDC92E47B7CD0097608D /* Build configuration list for PBXProject "Severed" */ = { + 20A7EDC92E47B7CD0097608D /* Build configuration list for PBXProject "OpenAppLock" */ = { isa = XCConfigurationList; buildConfigurations = ( 20A7EDEF2E47B7CF0097608D /* Debug */, @@ -581,7 +581,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 20A7EDF12E47B7CF0097608D /* Build configuration list for PBXNativeTarget "Severed" */ = { + 20A7EDF12E47B7CF0097608D /* Build configuration list for PBXNativeTarget "OpenAppLock" */ = { isa = XCConfigurationList; buildConfigurations = ( 20A7EDF22E47B7CF0097608D /* Debug */, @@ -590,7 +590,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 20A7EDF42E47B7CF0097608D /* Build configuration list for PBXNativeTarget "SeveredTests" */ = { + 20A7EDF42E47B7CF0097608D /* Build configuration list for PBXNativeTarget "OpenAppLockTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 20A7EDF52E47B7CF0097608D /* Debug */, @@ -599,7 +599,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 20A7EDF72E47B7CF0097608D /* Build configuration list for PBXNativeTarget "SeveredUITests" */ = { + 20A7EDF72E47B7CF0097608D /* Build configuration list for PBXNativeTarget "OpenAppLockUITests" */ = { isa = XCConfigurationList; buildConfigurations = ( 20A7EDF82E47B7CF0097608D /* Debug */, diff --git a/Severed.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/OpenAppLock.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from Severed.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to OpenAppLock.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/Severed/Assets.xcassets/AccentColor.colorset/Contents.json b/OpenAppLock/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from Severed/Assets.xcassets/AccentColor.colorset/Contents.json rename to OpenAppLock/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/Severed/Assets.xcassets/AppIcon.appiconset/Contents.json b/OpenAppLock/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from Severed/Assets.xcassets/AppIcon.appiconset/Contents.json rename to OpenAppLock/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/Severed/Assets.xcassets/Contents.json b/OpenAppLock/Assets.xcassets/Contents.json similarity index 100% rename from Severed/Assets.xcassets/Contents.json rename to OpenAppLock/Assets.xcassets/Contents.json diff --git a/Severed/Logic/RulePolicy.swift b/OpenAppLock/Logic/RulePolicy.swift similarity index 99% rename from Severed/Logic/RulePolicy.swift rename to OpenAppLock/Logic/RulePolicy.swift index d6dfe53..bb44c8a 100644 --- a/Severed/Logic/RulePolicy.swift +++ b/OpenAppLock/Logic/RulePolicy.swift @@ -1,6 +1,6 @@ // // RulePolicy.swift -// Severed +// OpenAppLock // import Foundation diff --git a/Severed/Logic/RuleSchedule.swift b/OpenAppLock/Logic/RuleSchedule.swift similarity index 99% rename from Severed/Logic/RuleSchedule.swift rename to OpenAppLock/Logic/RuleSchedule.swift index bb72f67..f30e4e4 100644 --- a/Severed/Logic/RuleSchedule.swift +++ b/OpenAppLock/Logic/RuleSchedule.swift @@ -1,6 +1,6 @@ // // RuleSchedule.swift -// Severed +// OpenAppLock // import Foundation diff --git a/Severed/Logic/RuleStatus.swift b/OpenAppLock/Logic/RuleStatus.swift similarity index 99% rename from Severed/Logic/RuleStatus.swift rename to OpenAppLock/Logic/RuleStatus.swift index 71403d1..ff52cab 100644 --- a/Severed/Logic/RuleStatus.swift +++ b/OpenAppLock/Logic/RuleStatus.swift @@ -1,6 +1,6 @@ // // RuleStatus.swift -// Severed +// OpenAppLock // import Foundation diff --git a/Severed/Models/BlockingRule.swift b/OpenAppLock/Models/BlockingRule.swift similarity index 99% rename from Severed/Models/BlockingRule.swift rename to OpenAppLock/Models/BlockingRule.swift index 28b67e1..201a94c 100644 --- a/Severed/Models/BlockingRule.swift +++ b/OpenAppLock/Models/BlockingRule.swift @@ -1,6 +1,6 @@ // // BlockingRule.swift -// Severed +// OpenAppLock // import Foundation diff --git a/Severed/Models/RuleDraft.swift b/OpenAppLock/Models/RuleDraft.swift similarity index 99% rename from Severed/Models/RuleDraft.swift rename to OpenAppLock/Models/RuleDraft.swift index 2517768..2759f96 100644 --- a/Severed/Models/RuleDraft.swift +++ b/OpenAppLock/Models/RuleDraft.swift @@ -1,6 +1,6 @@ // // RuleDraft.swift -// Severed +// OpenAppLock // import Foundation diff --git a/Severed/Models/RuleKind.swift b/OpenAppLock/Models/RuleKind.swift similarity index 99% rename from Severed/Models/RuleKind.swift rename to OpenAppLock/Models/RuleKind.swift index 32c4d3b..48a6321 100644 --- a/Severed/Models/RuleKind.swift +++ b/OpenAppLock/Models/RuleKind.swift @@ -1,6 +1,6 @@ // // RuleKind.swift -// Severed +// OpenAppLock // import Foundation diff --git a/Severed/Models/RulePreset.swift b/OpenAppLock/Models/RulePreset.swift similarity index 99% rename from Severed/Models/RulePreset.swift rename to OpenAppLock/Models/RulePreset.swift index 7140626..defad72 100644 --- a/Severed/Models/RulePreset.swift +++ b/OpenAppLock/Models/RulePreset.swift @@ -1,6 +1,6 @@ // // RulePreset.swift -// Severed +// OpenAppLock // import SwiftUI diff --git a/Severed/Models/Weekday.swift b/OpenAppLock/Models/Weekday.swift similarity index 99% rename from Severed/Models/Weekday.swift rename to OpenAppLock/Models/Weekday.swift index c9885ab..f89cd84 100644 --- a/Severed/Models/Weekday.swift +++ b/OpenAppLock/Models/Weekday.swift @@ -1,6 +1,6 @@ // // Weekday.swift -// Severed +// OpenAppLock // import Foundation diff --git a/Severed/Severed.entitlements b/OpenAppLock/OpenAppLock.entitlements similarity index 100% rename from Severed/Severed.entitlements rename to OpenAppLock/OpenAppLock.entitlements diff --git a/Severed/SeveredApp.swift b/OpenAppLock/OpenAppLockApp.swift similarity index 96% rename from Severed/SeveredApp.swift rename to OpenAppLock/OpenAppLockApp.swift index a510100..9d873e7 100644 --- a/Severed/SeveredApp.swift +++ b/OpenAppLock/OpenAppLockApp.swift @@ -1,6 +1,6 @@ // -// SeveredApp.swift -// Severed +// OpenAppLockApp.swift +// OpenAppLock // // Created by Brendan Chen on 2025.08.09. // @@ -9,7 +9,7 @@ import SwiftData import SwiftUI @main -struct SeveredApp: App { +struct OpenAppLockApp: App { private let container: ModelContainer @State private var authorization: ScreenTimeAuthorization @State private var enforcer: RuleEnforcer diff --git a/Severed/Services/LaunchConfiguration.swift b/OpenAppLock/Services/LaunchConfiguration.swift similarity index 99% rename from Severed/Services/LaunchConfiguration.swift rename to OpenAppLock/Services/LaunchConfiguration.swift index 86ec0b5..8cb9253 100644 --- a/Severed/Services/LaunchConfiguration.swift +++ b/OpenAppLock/Services/LaunchConfiguration.swift @@ -1,6 +1,6 @@ // // LaunchConfiguration.swift -// Severed +// OpenAppLock // import Foundation diff --git a/Severed/Services/RuleEnforcer.swift b/OpenAppLock/Services/RuleEnforcer.swift similarity index 98% rename from Severed/Services/RuleEnforcer.swift rename to OpenAppLock/Services/RuleEnforcer.swift index 7d745c6..96a9f4e 100644 --- a/Severed/Services/RuleEnforcer.swift +++ b/OpenAppLock/Services/RuleEnforcer.swift @@ -1,6 +1,6 @@ // // RuleEnforcer.swift -// Severed +// OpenAppLock // import Foundation diff --git a/Severed/Services/SampleRules.swift b/OpenAppLock/Services/SampleRules.swift similarity index 99% rename from Severed/Services/SampleRules.swift rename to OpenAppLock/Services/SampleRules.swift index 6411c1d..b97f600 100644 --- a/Severed/Services/SampleRules.swift +++ b/OpenAppLock/Services/SampleRules.swift @@ -1,6 +1,6 @@ // // SampleRules.swift -// Severed +// OpenAppLock // import Foundation diff --git a/Severed/Services/ScreenTimeAuthorization.swift b/OpenAppLock/Services/ScreenTimeAuthorization.swift similarity index 99% rename from Severed/Services/ScreenTimeAuthorization.swift rename to OpenAppLock/Services/ScreenTimeAuthorization.swift index 0eb7af4..bb9bffe 100644 --- a/Severed/Services/ScreenTimeAuthorization.swift +++ b/OpenAppLock/Services/ScreenTimeAuthorization.swift @@ -1,6 +1,6 @@ // // ScreenTimeAuthorization.swift -// Severed +// OpenAppLock // import FamilyControls diff --git a/Severed/Services/ShieldController.swift b/OpenAppLock/Services/ShieldController.swift similarity index 99% rename from Severed/Services/ShieldController.swift rename to OpenAppLock/Services/ShieldController.swift index 77b8282..38f2343 100644 --- a/Severed/Services/ShieldController.swift +++ b/OpenAppLock/Services/ShieldController.swift @@ -1,6 +1,6 @@ // // ShieldController.swift -// Severed +// OpenAppLock // import FamilyControls diff --git a/Severed/Views/Apps/AppsHomeView.swift b/OpenAppLock/Views/Apps/AppsHomeView.swift similarity index 99% rename from Severed/Views/Apps/AppsHomeView.swift rename to OpenAppLock/Views/Apps/AppsHomeView.swift index 8b09e7b..9b1dda6 100644 --- a/Severed/Views/Apps/AppsHomeView.swift +++ b/OpenAppLock/Views/Apps/AppsHomeView.swift @@ -1,6 +1,6 @@ // // AppsHomeView.swift -// Severed +// OpenAppLock // import SwiftData diff --git a/Severed/Views/Components/DayOfWeekPicker.swift b/OpenAppLock/Views/Components/DayOfWeekPicker.swift similarity index 99% rename from Severed/Views/Components/DayOfWeekPicker.swift rename to OpenAppLock/Views/Components/DayOfWeekPicker.swift index 3f32b1b..19d8d45 100644 --- a/Severed/Views/Components/DayOfWeekPicker.swift +++ b/OpenAppLock/Views/Components/DayOfWeekPicker.swift @@ -1,6 +1,6 @@ // // DayOfWeekPicker.swift -// Severed +// OpenAppLock // import SwiftUI diff --git a/Severed/Views/Onboarding/OnboardingView.swift b/OpenAppLock/Views/Onboarding/OnboardingView.swift similarity index 93% rename from Severed/Views/Onboarding/OnboardingView.swift rename to OpenAppLock/Views/Onboarding/OnboardingView.swift index 33d1361..9aa32f1 100644 --- a/Severed/Views/Onboarding/OnboardingView.swift +++ b/OpenAppLock/Views/Onboarding/OnboardingView.swift @@ -1,6 +1,6 @@ // // OnboardingView.swift -// Severed +// OpenAppLock // import SwiftUI @@ -39,7 +39,7 @@ struct OnboardingView: View { Image(systemName: "scissors") .font(.system(size: 56)) .foregroundStyle(.tint) - Text("Severed") + Text("OpenAppLock") .font(.largeTitle.bold()) Text("Block your most distracting apps with rules that keep you honest — on a schedule, with no way out when you choose Hard Mode.") .foregroundStyle(.secondary) @@ -56,13 +56,13 @@ struct OnboardingView: View { .font(.title.bold()) .multilineTextAlignment(.center) VStack(alignment: .leading, spacing: 14) { - bullet("shield.fill", "Severed uses Apple's Screen Time framework to block the apps you choose.") + bullet("shield.fill", "OpenAppLock uses Apple's Screen Time framework to block the apps you choose.") bullet("hand.raised.fill", "Your app activity stays on this device and is never collected.") bullet("gearshape.fill", "You can change this anytime in Settings.") } if authorization.status == .denied || authorization.lastRequestFailed { VStack(spacing: 10) { - Text("Screen Time access was declined. Severed can't block apps without it.") + Text("Screen Time access was declined. OpenAppLock can't block apps without it.") .font(.footnote) .foregroundStyle(.red) .multilineTextAlignment(.center) diff --git a/Severed/Views/RootView.swift b/OpenAppLock/Views/RootView.swift similarity index 98% rename from Severed/Views/RootView.swift rename to OpenAppLock/Views/RootView.swift index 60ae78b..6ed19f6 100644 --- a/Severed/Views/RootView.swift +++ b/OpenAppLock/Views/RootView.swift @@ -1,6 +1,6 @@ // // RootView.swift -// Severed +// OpenAppLock // import SwiftUI diff --git a/Severed/Views/Rules/AppSelectionSheet.swift b/OpenAppLock/Views/Rules/AppSelectionSheet.swift similarity index 99% rename from Severed/Views/Rules/AppSelectionSheet.swift rename to OpenAppLock/Views/Rules/AppSelectionSheet.swift index b76dfbf..8d75102 100644 --- a/Severed/Views/Rules/AppSelectionSheet.swift +++ b/OpenAppLock/Views/Rules/AppSelectionSheet.swift @@ -1,6 +1,6 @@ // // AppSelectionSheet.swift -// Severed +// OpenAppLock // import FamilyControls diff --git a/Severed/Views/Rules/NewRuleSheet.swift b/OpenAppLock/Views/Rules/NewRuleSheet.swift similarity index 99% rename from Severed/Views/Rules/NewRuleSheet.swift rename to OpenAppLock/Views/Rules/NewRuleSheet.swift index 692b75d..9feaee4 100644 --- a/Severed/Views/Rules/NewRuleSheet.swift +++ b/OpenAppLock/Views/Rules/NewRuleSheet.swift @@ -1,6 +1,6 @@ // // NewRuleSheet.swift -// Severed +// OpenAppLock // import SwiftData diff --git a/Severed/Views/Rules/RuleDetailSheet.swift b/OpenAppLock/Views/Rules/RuleDetailSheet.swift similarity index 99% rename from Severed/Views/Rules/RuleDetailSheet.swift rename to OpenAppLock/Views/Rules/RuleDetailSheet.swift index 2184486..5672210 100644 --- a/Severed/Views/Rules/RuleDetailSheet.swift +++ b/OpenAppLock/Views/Rules/RuleDetailSheet.swift @@ -1,6 +1,6 @@ // // RuleDetailSheet.swift -// Severed +// OpenAppLock // import SwiftData diff --git a/Severed/Views/Rules/RuleEditorView.swift b/OpenAppLock/Views/Rules/RuleEditorView.swift similarity index 99% rename from Severed/Views/Rules/RuleEditorView.swift rename to OpenAppLock/Views/Rules/RuleEditorView.swift index 13331db..dba03c8 100644 --- a/Severed/Views/Rules/RuleEditorView.swift +++ b/OpenAppLock/Views/Rules/RuleEditorView.swift @@ -1,6 +1,6 @@ // // RuleEditorView.swift -// Severed +// OpenAppLock // import SwiftUI diff --git a/SeveredTests/LaunchSupportTests.swift b/OpenAppLockTests/LaunchSupportTests.swift similarity index 87% rename from SeveredTests/LaunchSupportTests.swift rename to OpenAppLockTests/LaunchSupportTests.swift index b186e93..26d0d68 100644 --- a/SeveredTests/LaunchSupportTests.swift +++ b/OpenAppLockTests/LaunchSupportTests.swift @@ -1,19 +1,19 @@ // // LaunchSupportTests.swift -// SeveredTests +// OpenAppLockTests // import Foundation import Testing -@testable import Severed +@testable import OpenAppLock @MainActor @Suite("Launch configuration parsing") struct LaunchConfigurationTests { @Test("Defaults are production settings") func defaults() { - let config = LaunchConfiguration.parse(arguments: ["SeveredApp"]) + let config = LaunchConfiguration.parse(arguments: ["OpenAppLockApp"]) #expect(!config.isUITesting) #expect(config.onboardingCompleted == nil) #expect(config.seedScenario == nil) @@ -22,7 +22,7 @@ struct LaunchConfigurationTests { @Test("UI testing flags are recognized") func uiTestingFlags() { let config = LaunchConfiguration.parse(arguments: [ - "SeveredApp", "-ui-testing", "-onboarding-completed", "-seed-scenario=standard", + "OpenAppLockApp", "-ui-testing", "-onboarding-completed", "-seed-scenario=standard", ]) #expect(config.isUITesting) #expect(config.onboardingCompleted == true) @@ -31,13 +31,13 @@ struct LaunchConfigurationTests { @Test("Onboarding can be forced on") func onboardingRequired() { - let config = LaunchConfiguration.parse(arguments: ["SeveredApp", "-onboarding-required"]) + let config = LaunchConfiguration.parse(arguments: ["OpenAppLockApp", "-onboarding-required"]) #expect(config.onboardingCompleted == false) } @Test("Unknown seed scenarios are ignored") func unknownScenario() { - let config = LaunchConfiguration.parse(arguments: ["SeveredApp", "-seed-scenario=nope"]) + let config = LaunchConfiguration.parse(arguments: ["OpenAppLockApp", "-seed-scenario=nope"]) #expect(config.seedScenario == nil) } } diff --git a/SeveredTests/RuleEnforcerTests.swift b/OpenAppLockTests/RuleEnforcerTests.swift similarity index 98% rename from SeveredTests/RuleEnforcerTests.swift rename to OpenAppLockTests/RuleEnforcerTests.swift index d3bdf02..f77d03d 100644 --- a/SeveredTests/RuleEnforcerTests.swift +++ b/OpenAppLockTests/RuleEnforcerTests.swift @@ -1,12 +1,12 @@ // // RuleEnforcerTests.swift -// SeveredTests +// OpenAppLockTests // import Foundation import Testing -@testable import Severed +@testable import OpenAppLock @MainActor @Suite("Rule enforcement → shields") diff --git a/SeveredTests/RuleModelTests.swift b/OpenAppLockTests/RuleModelTests.swift similarity index 99% rename from SeveredTests/RuleModelTests.swift rename to OpenAppLockTests/RuleModelTests.swift index 421de1b..8f4a8f2 100644 --- a/SeveredTests/RuleModelTests.swift +++ b/OpenAppLockTests/RuleModelTests.swift @@ -1,13 +1,13 @@ // // RuleModelTests.swift -// SeveredTests +// OpenAppLockTests // import Foundation import SwiftData import Testing -@testable import Severed +@testable import OpenAppLock @MainActor @Suite("BlockingRule model & persistence") diff --git a/SeveredTests/RulePolicyTests.swift b/OpenAppLockTests/RulePolicyTests.swift similarity index 98% rename from SeveredTests/RulePolicyTests.swift rename to OpenAppLockTests/RulePolicyTests.swift index 884f21d..a0942ed 100644 --- a/SeveredTests/RulePolicyTests.swift +++ b/OpenAppLockTests/RulePolicyTests.swift @@ -1,12 +1,12 @@ // // RulePolicyTests.swift -// SeveredTests +// OpenAppLockTests // import Foundation import Testing -@testable import Severed +@testable import OpenAppLock @MainActor @Suite("Hard Mode policy") diff --git a/SeveredTests/RuleScheduleTests.swift b/OpenAppLockTests/RuleScheduleTests.swift similarity index 99% rename from SeveredTests/RuleScheduleTests.swift rename to OpenAppLockTests/RuleScheduleTests.swift index e1d9ebd..6780091 100644 --- a/SeveredTests/RuleScheduleTests.swift +++ b/OpenAppLockTests/RuleScheduleTests.swift @@ -1,12 +1,12 @@ // // RuleScheduleTests.swift -// SeveredTests +// OpenAppLockTests // import Foundation import Testing -@testable import Severed +@testable import OpenAppLock @MainActor @Suite("RuleSchedule window math") diff --git a/SeveredTests/RuleStatusTests.swift b/OpenAppLockTests/RuleStatusTests.swift similarity index 98% rename from SeveredTests/RuleStatusTests.swift rename to OpenAppLockTests/RuleStatusTests.swift index c4cc676..f7ec581 100644 --- a/SeveredTests/RuleStatusTests.swift +++ b/OpenAppLockTests/RuleStatusTests.swift @@ -1,12 +1,12 @@ // // RuleStatusTests.swift -// SeveredTests +// OpenAppLockTests // import Foundation import Testing -@testable import Severed +@testable import OpenAppLock @MainActor @Suite("Rule status derivation and labels") diff --git a/SeveredTests/TestSupport.swift b/OpenAppLockTests/TestSupport.swift similarity index 95% rename from SeveredTests/TestSupport.swift rename to OpenAppLockTests/TestSupport.swift index e63345b..c4c1b23 100644 --- a/SeveredTests/TestSupport.swift +++ b/OpenAppLockTests/TestSupport.swift @@ -1,11 +1,11 @@ // // TestSupport.swift -// SeveredTests +// OpenAppLockTests // import Foundation -@testable import Severed +@testable import OpenAppLock /// Fixed UTC gregorian calendar so schedule math is deterministic regardless /// of the machine running the tests. diff --git a/SeveredUITests/OnboardingUITests.swift b/OpenAppLockUITests/OnboardingUITests.swift similarity index 76% rename from SeveredUITests/OnboardingUITests.swift rename to OpenAppLockUITests/OnboardingUITests.swift index 76e0358..508463f 100644 --- a/SeveredUITests/OnboardingUITests.swift +++ b/OpenAppLockUITests/OnboardingUITests.swift @@ -1,6 +1,6 @@ // // OnboardingUITests.swift -// SeveredUITests +// OpenAppLockUITests // import XCTest @@ -11,10 +11,10 @@ final class OnboardingUITests: XCTestCase { } func testOnboardingWalksThroughPermissionToHome() throws { - let app = XCUIApplication.launchSevered(onboardingCompleted: false) + let app = XCUIApplication.launchOpenAppLock(onboardingCompleted: false) // Welcome step. - app.staticTexts["Severed"].waitToAppear() + app.staticTexts["OpenAppLock"].waitToAppear() app.buttons["onboardingContinueButton"].waitToAppear().tap() // Permission step: granting (mocked) lands on the Apps home screen. @@ -24,7 +24,7 @@ final class OnboardingUITests: XCTestCase { } func testCompletedOnboardingIsSkipped() throws { - let app = XCUIApplication.launchSevered(onboardingCompleted: true) + let app = XCUIApplication.launchOpenAppLock(onboardingCompleted: true) app.buttons["newRuleButton"].waitToAppear() XCTAssertFalse(app.buttons["onboardingContinueButton"].exists) } diff --git a/SeveredUITests/RuleCreationUITests.swift b/OpenAppLockUITests/RuleCreationUITests.swift similarity index 91% rename from SeveredUITests/RuleCreationUITests.swift rename to OpenAppLockUITests/RuleCreationUITests.swift index 15c0c8b..817caa3 100644 --- a/SeveredUITests/RuleCreationUITests.swift +++ b/OpenAppLockUITests/RuleCreationUITests.swift @@ -1,6 +1,6 @@ // // RuleCreationUITests.swift -// SeveredUITests +// OpenAppLockUITests // import XCTest @@ -11,7 +11,7 @@ final class RuleCreationUITests: XCTestCase { } func testCreateScheduleRuleFromTypeCard() throws { - let app = XCUIApplication.launchSevered() + let app = XCUIApplication.launchOpenAppLock() app.element("emptyRulesCard").waitToAppear() app.buttons["newRuleButton"].tap() @@ -32,7 +32,7 @@ final class RuleCreationUITests: XCTestCase { } func testCreateRuleFromPreset() throws { - let app = XCUIApplication.launchSevered() + let app = XCUIApplication.launchOpenAppLock() app.buttons["newRuleButton"].waitToAppear().tap() app.buttons["preset-work-time"].waitToAppear().tap() @@ -43,7 +43,7 @@ final class RuleCreationUITests: XCTestCase { } func testRenameRuleInEditor() throws { - let app = XCUIApplication.launchSevered() + let app = XCUIApplication.launchOpenAppLock() app.buttons["newRuleButton"].waitToAppear().tap() app.buttons["ruleKind-schedule"].waitToAppear().tap() @@ -62,7 +62,7 @@ final class RuleCreationUITests: XCTestCase { } func testDayTogglesFillRowAndHaveLargeTapTargets() throws { - let app = XCUIApplication.launchSevered() + let app = XCUIApplication.launchOpenAppLock() app.buttons["newRuleButton"].waitToAppear().tap() app.buttons["ruleKind-schedule"].waitToAppear().tap() @@ -80,7 +80,7 @@ final class RuleCreationUITests: XCTestCase { } func testDayTogglesUpdateSummary() throws { - let app = XCUIApplication.launchSevered() + let app = XCUIApplication.launchOpenAppLock() app.buttons["newRuleButton"].waitToAppear().tap() app.buttons["ruleKind-schedule"].waitToAppear().tap() @@ -92,7 +92,7 @@ final class RuleCreationUITests: XCTestCase { } func testCreateTimeLimitRule() throws { - let app = XCUIApplication.launchSevered() + let app = XCUIApplication.launchOpenAppLock() app.buttons["newRuleButton"].waitToAppear().tap() app.buttons["ruleKind-timeLimit"].waitToAppear().tap() @@ -108,7 +108,7 @@ final class RuleCreationUITests: XCTestCase { } func testAdultContentToggleFlowsToDetail() throws { - let app = XCUIApplication.launchSevered() + let app = XCUIApplication.launchOpenAppLock() app.buttons["newRuleButton"].waitToAppear().tap() app.buttons["ruleKind-schedule"].waitToAppear().tap() @@ -125,14 +125,14 @@ final class RuleCreationUITests: XCTestCase { } func testAdultContentDefaultsToAllowed() throws { - let app = XCUIApplication.launchSevered(seedScenario: "standard") + let app = XCUIApplication.launchOpenAppLock(seedScenario: "standard") app.buttons["ruleCard-Work Time"].waitToAppear().tap() let row = app.element("detailRow-Adult websites").waitToAppear() XCTAssertTrue(row.label.contains("Allowed"), "Got: \(row.label)") } func testEditorSupportsNativeSwipeBack() throws { - let app = XCUIApplication.launchSevered() + let app = XCUIApplication.launchOpenAppLock() app.buttons["newRuleButton"].waitToAppear().tap() app.buttons["ruleKind-schedule"].waitToAppear().tap() app.staticTexts["ruleEditorTitle"].waitToAppear() @@ -147,7 +147,7 @@ final class RuleCreationUITests: XCTestCase { } func testNewRuleSheetShowsTypesAndPresets() throws { - let app = XCUIApplication.launchSevered() + let app = XCUIApplication.launchOpenAppLock() app.buttons["newRuleButton"].waitToAppear().tap() app.buttons["ruleKind-schedule"].waitToAppear() diff --git a/SeveredUITests/RuleManagementUITests.swift b/OpenAppLockUITests/RuleManagementUITests.swift similarity index 88% rename from SeveredUITests/RuleManagementUITests.swift rename to OpenAppLockUITests/RuleManagementUITests.swift index f6577bf..5b8bd11 100644 --- a/SeveredUITests/RuleManagementUITests.swift +++ b/OpenAppLockUITests/RuleManagementUITests.swift @@ -1,6 +1,6 @@ // // RuleManagementUITests.swift -// SeveredUITests +// OpenAppLockUITests // import XCTest @@ -13,7 +13,7 @@ final class RuleManagementUITests: XCTestCase { } func testDetailShowsLiveStatusAndFacts() throws { - let app = XCUIApplication.launchSevered(seedScenario: "standard") + let app = XCUIApplication.launchOpenAppLock(seedScenario: "standard") app.buttons["ruleCard-Work Time"].waitToAppear().tap() @@ -29,7 +29,7 @@ final class RuleManagementUITests: XCTestCase { } func testEditRuleTogglesHardModeOn() throws { - let app = XCUIApplication.launchSevered(seedScenario: "standard") + let app = XCUIApplication.launchOpenAppLock(seedScenario: "standard") app.buttons["ruleCard-Sleep"].waitToAppear().tap() app.buttons["editRuleButton"].waitToAppear().tap() @@ -43,7 +43,7 @@ final class RuleManagementUITests: XCTestCase { } func testDisableRule() throws { - let app = XCUIApplication.launchSevered(seedScenario: "standard") + let app = XCUIApplication.launchOpenAppLock(seedScenario: "standard") app.buttons["ruleCard-Sleep"].waitToAppear().tap() app.buttons["editRuleButton"].waitToAppear().tap() @@ -64,7 +64,7 @@ final class RuleManagementUITests: XCTestCase { } func testDeleteRuleRemovesCard() throws { - let app = XCUIApplication.launchSevered(seedScenario: "standard") + let app = XCUIApplication.launchOpenAppLock(seedScenario: "standard") app.buttons["ruleCard-Sleep"].waitToAppear().tap() app.buttons["editRuleButton"].waitToAppear().tap() @@ -82,7 +82,7 @@ final class RuleManagementUITests: XCTestCase { } func testUnblockActiveSoftRule() throws { - let app = XCUIApplication.launchSevered(seedScenario: "standard") + let app = XCUIApplication.launchOpenAppLock(seedScenario: "standard") // The active rule surfaces in Blocked Apps; unblocking pauses it. app.buttons["blockedTile-Work Time"].waitToAppear().tap() @@ -100,7 +100,7 @@ final class HardModeUITests: XCTestCase { } func testHardLockedRuleCannotBeEdited() throws { - let app = XCUIApplication.launchSevered(seedScenario: "hard-mode-active") + let app = XCUIApplication.launchOpenAppLock(seedScenario: "hard-mode-active") app.buttons["ruleCard-Locked In"].waitToAppear().tap() @@ -111,7 +111,7 @@ final class HardModeUITests: XCTestCase { } func testHardLockedRuleCannotBeUnblocked() throws { - let app = XCUIApplication.launchSevered(seedScenario: "hard-mode-active") + let app = XCUIApplication.launchOpenAppLock(seedScenario: "hard-mode-active") app.buttons["blockedTile-Locked In"].waitToAppear().tap() @@ -126,7 +126,7 @@ final class HardModeUITests: XCTestCase { } func testSoftRuleUnblockOfferedButHardRuleRefused() throws { - let app = XCUIApplication.launchSevered(seedScenario: "standard") + let app = XCUIApplication.launchOpenAppLock(seedScenario: "standard") app.buttons["blockedTile-Work Time"].waitToAppear().tap() // Soft rule: the confirmation dialog appears instead of the refusal alert. diff --git a/SeveredUITests/UITestSupport.swift b/OpenAppLockUITests/UITestSupport.swift similarity index 96% rename from SeveredUITests/UITestSupport.swift rename to OpenAppLockUITests/UITestSupport.swift index 3438f38..0304f87 100644 --- a/SeveredUITests/UITestSupport.swift +++ b/OpenAppLockUITests/UITestSupport.swift @@ -1,6 +1,6 @@ // // UITestSupport.swift -// SeveredUITests +// OpenAppLockUITests // import XCTest @@ -8,7 +8,7 @@ import XCTest extension XCUIApplication { /// Launches the app in UI-testing mode: in-memory storage, mocked Screen /// Time authorization, and no shield side effects. - static func launchSevered( + static func launchOpenAppLock( onboardingCompleted: Bool = true, seedScenario: String? = nil ) -> XCUIApplication { diff --git a/docs/RULES_FEATURE_SPEC.md b/docs/RULES_FEATURE_SPEC.md index 51f693e..7c44670 100644 --- a/docs/RULES_FEATURE_SPEC.md +++ b/docs/RULES_FEATURE_SPEC.md @@ -1,9 +1,9 @@ -# Severed — "Rules" Feature Spec (derived from Opal screen recording) +# OpenAppLock — "Rules" Feature Spec (derived from Opal screen recording) Source: `ScreenRecording_06-12-2026 11-26-19_1.MP4` (iPhone, 4:29). The rules feature appears roughly between 1:00–3:00 of the recording, on Opal's "My Apps" tab. This spec describes what was observed, then maps it onto an implementation plan -for Severed. +for OpenAppLock. --- @@ -126,7 +126,7 @@ Presented from "+ New". Full-height sheet, scrollable. and a circular "+" button bottom-right. Tapping anywhere opens the Schedule editor pre-filled with the preset's name/times/days. -> **Navigation (Severed):** picking a rule type or preset **pushes** the +> **Navigation (OpenAppLock):** picking a rule type or preset **pushes** the > editor inside the sheet via native SwiftUI navigation (`NavigationStack` + > `navigationDestination(item:)`), so the system push animation and > edge-swipe-back work; the editor keeps its custom header chrome. @@ -150,7 +150,7 @@ Sections (each an inset rounded group with a small icon + caption header): - Row: `Selected Apps` → `N Apps ›` — pushes the App Picker. 4. **Hard Mode** `⚡PRO` badge — subtitle "No unblocks allowed"; trailing toggle. -5. **Block Adult Content** *(Severed addition — not in the Opal video)* — +5. **Block Adult Content** *(OpenAppLock addition — not in the Opal video)* — subtitle "Filter adult websites while this rule is active"; trailing toggle. Maps to Screen Time's web-content filter (`ManagedSettingsStore.webContent.blockedByFilter = .auto(...)`), applied @@ -208,7 +208,7 @@ Full-height sheet: > Implementation note: Opal ships its own app categorization. On iOS, third > 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 Severed should +> 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. @@ -241,7 +241,7 @@ Full-height sheet: --- -## 5. Implementation plan for Severed +## 5. Implementation plan for OpenAppLock ### 5.1 Frameworks & capabilities @@ -334,7 +334,7 @@ enum SelectionMode: String, Codable { case block, allowOnly } ## 6. Native UI re-skin (current presentation) -Severed has since replaced the Opal-style custom presentation with the bare +OpenAppLock has since replaced the Opal-style custom presentation with the bare iOS design language, keeping the backend (models, logic, services), the flows, and the accessibility identifiers intact. Sections 1–5 remain as the reference for *what* the feature does; presentation now maps as follows: