# WristCode watch app SwiftUI, watch only, Swift 6 with strict concurrency, and no dependencies. It talks to the gateway over HTTPS + JSON as described in [docs/api.md](../docs/api.md); `WristCode/API/Models.swift` mirrors [gateway/src/contract.ts](../gateway/src/contract.ts). ## Build and test ```sh cd watch xcodegen generate # the .xcodeproj is generated and gitignored xcodebuild -scheme WristCode -destination 'platform=watchOS Simulator,name=Apple Watch Series 12 (46mm)' build xcodebuild -scheme WristCode -destination 'platform=watchOS Simulator,name=Apple Watch Series 12 (46mm)' test ``` ## TestFlight The App Store only takes a watch-only app inside an empty iOS stub, so `project.yml` has two app targets, the same pair Xcode's "Watch-only App" template makes: | Target | Bundle ID | Job | | --- | --- | --- | | `WristCodeContainer` | `org.gbrown.wristcode` | iOS stub that owns the App Store Connect record and embeds the watch app | | `WristCode` | `org.gbrown.wristcode.watchkitapp` | The watch app, and the APNs topic | ```sh scripts/testflight.sh # archive, export and upload to App Store Connect scripts/testflight.sh --no-upload # archive and export an .ipa to build/export- only ``` The build number defaults to a `YYYYMMDDHHMM` timestamp (override it with `BUILD_NUMBER`). Signing is automatic through the App Store Connect API key in `ASC_KEY_PATH`, `ASC_KEY_ID` and `ASC_ISSUER_ID`, which default to the key in `~/.appstoreconnect/private_keys`. The entitlements file says `aps-environment: development`; the App Store export re-signs it as `production`. Release builds register their token with the gateway as `production`, Debug builds as `sandbox`. ## Demo mode `DemoGateway` serves fixture data shaped like the docs/api.md examples, and it reacts to writes: Allow moves a thread to working, a reply restarts a finished thread. The SwiftUI previews use it, the pairing screen has a "Try the demo" button, and launch arguments open a screen directly: ```sh xcrun simctl launch org.gbrown.wristcode.watchkitapp -demo # feed xcrun simctl launch org.gbrown.wristcode.watchkitapp -demo -thread littleman/t-next # thread xcrun simctl launch org.gbrown.wristcode.watchkitapp -demo -screen new # new thread ``` `screenshots/` holds the screens captured this way. ## Layout | Path | Job | | --- | --- | | `WristCodeApp.swift` | App entry, root navigation, `WKApplicationDelegate` for APNs registration | | `AppModel.swift` | Paired, demo or unpaired; navigation path; the feed; 401 sends you back to pairing | | `API/GatewayClient.swift` | `GatewayAPI` protocol and the URLSession client | | `API/Models.swift` | Codable mirror of the contract | | `Auth/DeviceStore.swift` | Device token and gateway URL in the Keychain | | `Demo/DemoGateway.swift` | In-memory gateway with fixtures | | `Views/` | Pair, Feed, Thread, New thread, and the mock B theme | | `Notifications/NotificationHandler.swift` | Categories `approval`, `finished`, `failed`, `input`, `host` and their actions |