commit aa010cf874cd6db542dfb6eb5a2457b6bb15df64 Author: jay Date: Fri May 15 13:19:48 2026 +0200 feat(T-2.0): Xcode project scaffold — SwiftUI shell, SwiftTerm + Starscream SPM deps - xcodegen project.yml: de.vpsj.pi-remote, team KNXX8R3648, iOS 17+ - SwiftTerm 1.13.0, Starscream 4.0.8 resolved - App entry point + ContentView hello shell - Push Notifications entitlement (aps-environment: development) - pi-remote:// URL scheme registered - NSCameraUsageDescription (QR pairing), NSFaceIDUsageDescription - UIBackgroundModes: remote-notification diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb20f92 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# Xcode +build/ +DerivedData/ +*.xcuserstate +*.xcuserdatad/ +*.xcworkspace/xcuserdata/ +xcuserdata/ + +# SPM +.build/ +.swiftpm/ +*.resolved + +# macOS +.DS_Store + +# Credentials — never commit +*.p8 +*.p12 +*.cer +secrets/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..e6d41fc --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +# pi-remote iOS + +Native iOS app for the [pi-remote-control](https://git.vpsj.de/jay/pi-remote-control) sidecar. + +## Requirements + +- Xcode 16.4+ +- iOS 17.0+ device +- pi-remote-control sidecar running (Phase 1) + +## Building + +```bash +# Open in Xcode (first time: Xcode downloads device support files automatically) +open piRemote.xcodeproj + +# Or via CLI (after first Xcode open with device connected): +xcodebuild build -project piRemote.xcodeproj -scheme piRemote \ + -destination "platform=iOS,name=" \ + CODE_SIGNING_STYLE=Automatic DEVELOPMENT_TEAM=KNXX8R3648 +``` + +## Project structure + +``` +Sources/ +├── App/ — @main entry, ContentView, Assets +├── Core/ +│ ├── Network/ — WebSocketClient, FrameCodec, ResumeCursor, TLS pinning +│ ├── Auth/ — Keychain, Pairing (QR exchange) +│ ├── Sessions/ — SessionRegistry, SessionConnection, PreConnectPool +│ ├── Push/ — APNs NotificationDelegate, DeviceTokenRegistrar +│ └── Persistence/ — ScrollbackCache, Preferences +└── UI/ + ├── Terminal/ — SwiftTerm wrapper, themes, fonts + ├── Input/ — ModifierBar, sticky Ctrl, paste sheet + ├── Status/ — StatusBar (pi state) + ├── Sessions/ — SessionSwitcher + ├── Pairing/ — QR scanner flow + └── Settings/ — Face-ID gate, sidecar info +``` + +## Dependencies (via SPM) + +- [SwiftTerm](https://github.com/migueldeicaza/SwiftTerm) — terminal emulator +- [Starscream](https://github.com/daltoniam/Starscream) — WebSocket client + +## Apple Developer setup (one-time) + +1. In [Apple Developer Portal](https://developer.apple.com/account): + - Create App ID: `de.vpsj.pi-remote`, enable **Push Notifications** + - Generate an **APNs Auth Key** (`.p8`) — *download once, keep safe* + - Note your **Key ID** and **Team ID** (`KNXX8R3648`) +2. Copy `.p8` key to `~/.local/share/pi-remote/apns/AuthKey_.p8` +3. Update `[apns]` section in pi-remote-control config + +## Status + +Phase 2 — in development. See `pi-remote-control/docs/PHASE-2-ios-mvp.md`. diff --git a/Sources/App/Assets.xcassets/AccentColor.colorset/Contents.json b/Sources/App/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..848d388 --- /dev/null +++ b/Sources/App/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,4 @@ +{ + "colors": [{"idiom": "universal"}], + "info": { "author": "xcode", "version": 1 } +} diff --git a/Sources/App/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sources/App/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..355335e --- /dev/null +++ b/Sources/App/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1 @@ +{ "images": [], "info": { "author": "xcode", "version": 1 } } diff --git a/Sources/App/Assets.xcassets/Contents.json b/Sources/App/Assets.xcassets/Contents.json new file mode 100644 index 0000000..ac502da --- /dev/null +++ b/Sources/App/Assets.xcassets/Contents.json @@ -0,0 +1 @@ +{ "info": { "author": "xcode", "version": 1 } } diff --git a/Sources/App/ContentView.swift b/Sources/App/ContentView.swift new file mode 100644 index 0000000..e1d0fab --- /dev/null +++ b/Sources/App/ContentView.swift @@ -0,0 +1,22 @@ +import SwiftUI + +struct ContentView: View { + var body: some View { + VStack(spacing: 16) { + Image(systemName: "terminal") + .imageScale(.large) + .font(.system(size: 60)) + .foregroundStyle(.green) + Text("pi remote") + .font(.largeTitle.monospaced()) + Text("Phase 2 — in development") + .font(.caption) + .foregroundStyle(.secondary) + } + .padding() + } +} + +#Preview { + ContentView() +} diff --git a/Sources/App/Info.plist b/Sources/App/Info.plist new file mode 100644 index 0000000..ee55999 --- /dev/null +++ b/Sources/App/Info.plist @@ -0,0 +1,50 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleURLTypes + + + CFBundleURLSchemes + + pi-remote + + + + CFBundleVersion + 1 + NSCameraUsageDescription + Used to scan QR codes for pairing. + NSFaceIDUsageDescription + Protects access to your pi sessions. + UIBackgroundModes + + remote-notification + + UILaunchScreen + + UIColorName + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Sources/App/Preview Content/Preview Assets.xcassets/Contents.json b/Sources/App/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 0000000..ac502da --- /dev/null +++ b/Sources/App/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1 @@ +{ "info": { "author": "xcode", "version": 1 } } diff --git a/Sources/App/piRemote.entitlements b/Sources/App/piRemote.entitlements new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/Sources/App/piRemote.entitlements @@ -0,0 +1,5 @@ + + + + + diff --git a/Sources/App/piRemoteApp.swift b/Sources/App/piRemoteApp.swift new file mode 100644 index 0000000..fb49c1c --- /dev/null +++ b/Sources/App/piRemoteApp.swift @@ -0,0 +1,10 @@ +import SwiftUI + +@main +struct piRemoteApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/piRemote.xcodeproj/project.pbxproj b/piRemote.xcodeproj/project.pbxproj new file mode 100644 index 0000000..6423505 --- /dev/null +++ b/piRemote.xcodeproj/project.pbxproj @@ -0,0 +1,605 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXBuildFile section */ + 30E07FF586EABBBB8C70AE60 /* piRemoteApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73D747BC787A24B4E225B142 /* piRemoteApp.swift */; }; + 56096DB64F700FC00C4D58CE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AFF032BC30D513204211ADA5 /* Assets.xcassets */; }; + 873DC9D5342E8F4AF2C5BEE9 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = CCBD990EEA7AD9DCF714DF97 /* Starscream */; }; + D77D662C3311D9646BE57596 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6BDDFB0C0D1D6D6FB490BA8D /* Preview Assets.xcassets */; }; + F6C311D17A8DAA4F19464E25 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 188683139B863ED1AC03A1BB /* ContentView.swift */; }; + FADABBF0D0229D84832D3B78 /* SwiftTerm in Frameworks */ = {isa = PBXBuildFile; productRef = D095700C52C60FDA2CB38679 /* SwiftTerm */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + B301DDFED8092F66145718E3 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B5A2356AA5371FBA25136FA6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4910ACCEB67B73CBA3440774; + remoteInfo = piRemote; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 0E401DECD467A1D3AB030610 /* piRemote.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = piRemote.entitlements; sourceTree = ""; }; + 188683139B863ED1AC03A1BB /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 2E2370A3190FDC144C822FF6 /* piRemote.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = piRemote.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 658CB2FCA96A8913B1753B1C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 6BDDFB0C0D1D6D6FB490BA8D /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 73D747BC787A24B4E225B142 /* piRemoteApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = piRemoteApp.swift; sourceTree = ""; }; + AFF032BC30D513204211ADA5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + CD24C7095F23AF63CCFB23F0 /* piRemoteTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = piRemoteTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + C346201325F7F2939EB7A792 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FADABBF0D0229D84832D3B78 /* SwiftTerm in Frameworks */, + 873DC9D5342E8F4AF2C5BEE9 /* Starscream in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 161D89B853288EC766A0767D /* Products */ = { + isa = PBXGroup; + children = ( + 2E2370A3190FDC144C822FF6 /* piRemote.app */, + CD24C7095F23AF63CCFB23F0 /* piRemoteTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 1909DBD374F6922644BF6B4D /* Sessions */ = { + isa = PBXGroup; + children = ( + ); + path = Sessions; + sourceTree = ""; + }; + 35A8DD31F76D71B8CDCDDC8D /* Core */ = { + isa = PBXGroup; + children = ( + ED7AFC5C0EF365C5831C7245 /* Auth */, + DCF268D44CD471E86B6192B0 /* Network */, + D484C43F0BAEF3990BB88D8F /* Persistence */, + 8E5B4A1E4AE8D09F6E581E02 /* Push */, + 1909DBD374F6922644BF6B4D /* Sessions */, + ); + path = Core; + sourceTree = ""; + }; + 35F24B7F065B257F93810E5B /* Sessions */ = { + isa = PBXGroup; + children = ( + ); + path = Sessions; + sourceTree = ""; + }; + 49209A78102230A37C0FF8D0 /* Terminal */ = { + isa = PBXGroup; + children = ( + ); + path = Terminal; + sourceTree = ""; + }; + 58E55A616A534D72FF9D4299 /* Preview Content */ = { + isa = PBXGroup; + children = ( + 6BDDFB0C0D1D6D6FB490BA8D /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + 69990A9885FB5B354E73AB90 /* Tests */ = { + isa = PBXGroup; + children = ( + C06242078CD1DD2BD7C7A4FA /* CoreTests */, + ); + path = Tests; + sourceTree = ""; + }; + 8A477F7D38B42EEB3F70323F /* Pairing */ = { + isa = PBXGroup; + children = ( + ); + path = Pairing; + sourceTree = ""; + }; + 8E5B4A1E4AE8D09F6E581E02 /* Push */ = { + isa = PBXGroup; + children = ( + ); + path = Push; + sourceTree = ""; + }; + 9B44B95A69D3C0C00BCF32FB = { + isa = PBXGroup; + children = ( + C8D95B3C16FEE9C9FBE38FDE /* Sources */, + 69990A9885FB5B354E73AB90 /* Tests */, + 161D89B853288EC766A0767D /* Products */, + ); + sourceTree = ""; + }; + 9DF960DFB90BF425282C35D0 /* Input */ = { + isa = PBXGroup; + children = ( + ); + path = Input; + sourceTree = ""; + }; + C06242078CD1DD2BD7C7A4FA /* CoreTests */ = { + isa = PBXGroup; + children = ( + ); + path = CoreTests; + sourceTree = ""; + }; + C7FBB3C467939760D2971070 /* Status */ = { + isa = PBXGroup; + children = ( + ); + path = Status; + sourceTree = ""; + }; + C8D95B3C16FEE9C9FBE38FDE /* Sources */ = { + isa = PBXGroup; + children = ( + ECEA8716C9698DDD14367AC9 /* App */, + 35A8DD31F76D71B8CDCDDC8D /* Core */, + E68CFF24811DAA2A2ACE2EB3 /* UI */, + ); + path = Sources; + sourceTree = ""; + }; + D484C43F0BAEF3990BB88D8F /* Persistence */ = { + isa = PBXGroup; + children = ( + ); + path = Persistence; + sourceTree = ""; + }; + DCF268D44CD471E86B6192B0 /* Network */ = { + isa = PBXGroup; + children = ( + ); + path = Network; + sourceTree = ""; + }; + E68CFF24811DAA2A2ACE2EB3 /* UI */ = { + isa = PBXGroup; + children = ( + 9DF960DFB90BF425282C35D0 /* Input */, + 8A477F7D38B42EEB3F70323F /* Pairing */, + 35F24B7F065B257F93810E5B /* Sessions */, + F681ED5F43C5283558361FAC /* Settings */, + C7FBB3C467939760D2971070 /* Status */, + 49209A78102230A37C0FF8D0 /* Terminal */, + ); + path = UI; + sourceTree = ""; + }; + ECEA8716C9698DDD14367AC9 /* App */ = { + isa = PBXGroup; + children = ( + AFF032BC30D513204211ADA5 /* Assets.xcassets */, + 188683139B863ED1AC03A1BB /* ContentView.swift */, + 658CB2FCA96A8913B1753B1C /* Info.plist */, + 0E401DECD467A1D3AB030610 /* piRemote.entitlements */, + 73D747BC787A24B4E225B142 /* piRemoteApp.swift */, + 58E55A616A534D72FF9D4299 /* Preview Content */, + ); + path = App; + sourceTree = ""; + }; + ED7AFC5C0EF365C5831C7245 /* Auth */ = { + isa = PBXGroup; + children = ( + ); + path = Auth; + sourceTree = ""; + }; + F681ED5F43C5283558361FAC /* Settings */ = { + isa = PBXGroup; + children = ( + ); + path = Settings; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 2C3DD20A67B90DDE04FDEE41 /* piRemoteTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = C553B125FB09A7C04D602AE2 /* Build configuration list for PBXNativeTarget "piRemoteTests" */; + buildPhases = ( + 6DDDB771E08071591D668B0A /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + 2965A47833122165B123DA9B /* PBXTargetDependency */, + ); + name = piRemoteTests; + packageProductDependencies = ( + ); + productName = piRemoteTests; + productReference = CD24C7095F23AF63CCFB23F0 /* piRemoteTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 4910ACCEB67B73CBA3440774 /* piRemote */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7D4FC8D9F69801EED9D13DA7 /* Build configuration list for PBXNativeTarget "piRemote" */; + buildPhases = ( + 26E05B31335CA4B7811BD0F7 /* Sources */, + 31D09DC5D7BBE74682559B5C /* Resources */, + C346201325F7F2939EB7A792 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = piRemote; + packageProductDependencies = ( + D095700C52C60FDA2CB38679 /* SwiftTerm */, + CCBD990EEA7AD9DCF714DF97 /* Starscream */, + ); + productName = piRemote; + productReference = 2E2370A3190FDC144C822FF6 /* piRemote.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B5A2356AA5371FBA25136FA6 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1640; + TargetAttributes = { + 2C3DD20A67B90DDE04FDEE41 = { + DevelopmentTeam = KNXX8R3648; + ProvisioningStyle = Automatic; + }; + 4910ACCEB67B73CBA3440774 = { + DevelopmentTeam = KNXX8R3648; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 193C24354F678E5C0C3CC4D1 /* Build configuration list for PBXProject "piRemote" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + Base, + en, + ); + mainGroup = 9B44B95A69D3C0C00BCF32FB; + minimizedProjectReferenceProxies = 1; + packageReferences = ( + 310EBBB8ACF6C94857EC49A2 /* XCRemoteSwiftPackageReference "Starscream" */, + D0AD1BFEB65E0B0DA2A16FC7 /* XCRemoteSwiftPackageReference "SwiftTerm" */, + ); + preferredProjectObjectVersion = 77; + productRefGroup = 161D89B853288EC766A0767D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 4910ACCEB67B73CBA3440774 /* piRemote */, + 2C3DD20A67B90DDE04FDEE41 /* piRemoteTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 31D09DC5D7BBE74682559B5C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 56096DB64F700FC00C4D58CE /* Assets.xcassets in Resources */, + D77D662C3311D9646BE57596 /* Preview Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 26E05B31335CA4B7811BD0F7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F6C311D17A8DAA4F19464E25 /* ContentView.swift in Sources */, + 30E07FF586EABBBB8C70AE60 /* piRemoteApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6DDDB771E08071591D668B0A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 2965A47833122165B123DA9B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4910ACCEB67B73CBA3440774 /* piRemote */; + targetProxy = B301DDFED8092F66145718E3 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 0E6C5BC837AB6537852A7F92 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = de.vpsj.piRemoteTests; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/piRemote.app/piRemote"; + }; + name = Debug; + }; + 2E146A9E4FCF9F393A9D41C0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = Sources/App/piRemote.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + INFOPLIST_FILE = Sources/App/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "de.vpsj.pi-remote"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 30909A3060849FE14F196221 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = KNXX8R3648; + ENABLE_BITCODE = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "DEBUG=1", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + MARKETING_VERSION = 0.1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; + }; + name = Debug; + }; + 3C99CD7AE03C725305B787EA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = KNXX8R3648; + ENABLE_BITCODE = NO; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + MARKETING_VERSION = 0.1.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 6.0; + }; + name = Release; + }; + BCA8D933602A624F296AC6AB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = Sources/App/piRemote.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + INFOPLIST_FILE = Sources/App/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "de.vpsj.pi-remote"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + BCD063DCDE72A18833A2C42B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = de.vpsj.piRemoteTests; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/piRemote.app/piRemote"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 193C24354F678E5C0C3CC4D1 /* Build configuration list for PBXProject "piRemote" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 30909A3060849FE14F196221 /* Debug */, + 3C99CD7AE03C725305B787EA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 7D4FC8D9F69801EED9D13DA7 /* Build configuration list for PBXNativeTarget "piRemote" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BCA8D933602A624F296AC6AB /* Debug */, + 2E146A9E4FCF9F393A9D41C0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + C553B125FB09A7C04D602AE2 /* Build configuration list for PBXNativeTarget "piRemoteTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0E6C5BC837AB6537852A7F92 /* Debug */, + BCD063DCDE72A18833A2C42B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 310EBBB8ACF6C94857EC49A2 /* XCRemoteSwiftPackageReference "Starscream" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/daltoniam/Starscream"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 4.0.0; + }; + }; + D0AD1BFEB65E0B0DA2A16FC7 /* XCRemoteSwiftPackageReference "SwiftTerm" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/migueldeicaza/SwiftTerm"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.2.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + CCBD990EEA7AD9DCF714DF97 /* Starscream */ = { + isa = XCSwiftPackageProductDependency; + package = 310EBBB8ACF6C94857EC49A2 /* XCRemoteSwiftPackageReference "Starscream" */; + productName = Starscream; + }; + D095700C52C60FDA2CB38679 /* SwiftTerm */ = { + isa = XCSwiftPackageProductDependency; + package = D0AD1BFEB65E0B0DA2A16FC7 /* XCRemoteSwiftPackageReference "SwiftTerm" */; + productName = SwiftTerm; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = B5A2356AA5371FBA25136FA6 /* Project object */; +} diff --git a/piRemote.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/piRemote.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/piRemote.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/piRemote.xcodeproj/xcshareddata/xcschemes/piRemote.xcscheme b/piRemote.xcodeproj/xcshareddata/xcschemes/piRemote.xcscheme new file mode 100644 index 0000000..a652022 --- /dev/null +++ b/piRemote.xcodeproj/xcshareddata/xcschemes/piRemote.xcscheme @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/project.yml b/project.yml new file mode 100644 index 0000000..c8588c0 --- /dev/null +++ b/project.yml @@ -0,0 +1,84 @@ +name: piRemote +options: + bundleIdPrefix: de.vpsj + deploymentTarget: + iOS: "17.0" + xcodeVersion: "16.4" + generateEmptyDirectories: true + createIntermediateGroups: true + +settings: + base: + SWIFT_VERSION: 6.0 + MARKETING_VERSION: 0.1.0 + CURRENT_PROJECT_VERSION: 1 + DEVELOPMENT_TEAM: KNXX8R3648 + CODE_SIGN_STYLE: Automatic + ENABLE_BITCODE: NO + +packages: + SwiftTerm: + url: https://github.com/migueldeicaza/SwiftTerm + from: 1.2.0 + Starscream: + url: https://github.com/daltoniam/Starscream + from: 4.0.0 + +schemes: + piRemote: + build: + targets: + piRemote: all + run: + config: Debug + test: + config: Debug + targets: + - piRemoteTests + archive: + config: Release + +targets: + piRemote: + type: application + platform: iOS + deploymentTarget: "17.0" + sources: + - path: Sources + resources: + - path: Sources/App/Assets.xcassets + - path: Sources/App/Preview Content + settings: + base: + PRODUCT_BUNDLE_IDENTIFIER: de.vpsj.pi-remote + INFOPLIST_FILE: Sources/App/Info.plist + ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon + entitlements: + path: Sources/App/piRemote.entitlements + dependencies: + - package: SwiftTerm + - package: Starscream + info: + path: Sources/App/Info.plist + properties: + UILaunchScreen: + UIColorName: "" + UISupportedInterfaceOrientations: + - UIInterfaceOrientationPortrait + - UIInterfaceOrientationLandscapeLeft + - UIInterfaceOrientationLandscapeRight + NSCameraUsageDescription: "Used to scan QR codes for pairing." + NSFaceIDUsageDescription: "Protects access to your pi sessions." + UIBackgroundModes: + - remote-notification + CFBundleURLTypes: + - CFBundleURLSchemes: + - pi-remote + + piRemoteTests: + type: bundle.unit-test + platform: iOS + sources: + - path: Tests/CoreTests + dependencies: + - target: piRemote