Files
ipodderx-app/ios/project.yml
Ray Slakinski f88ae657f3 An API client for ipx, and its event stream (#1)
Everything native needs this first, and it is worth having whatever happens
to the rest: a CarPlay browse tree is built from exactly these calls.

API covers what a client reads and writes -- feeds, entries with the
server's own paging, filtering, sorting and search, read and pinned,
position, read-all, download, delete, fetch -- and APIModels is what ipx
sends, with the server's field names kept so a type here can be checked
against web.rs without translating first. It sends nothing of its own to
authenticate: ipx decides who is asking by cookie and CookieBridge keeps
HTTPCookieStorage in step, which is the same property that lets a plain
<audio src> work.

Events reads /api/events with URLSession's byte stream, so there is no new
dependency. An event this build has never heard of decodes as .other rather
than throwing, because a new one on the server must not stop the stream. It
reconnects with a backoff: a deploy closes the stream cleanly and should be
picked straight back up, a daemon that is down should not be hammered.

Library is gone, folded into API. Two clients writing positions was one too
many, and the page's forwarded beacon no longer carries a path: it asks the
host to save, and the host uses its own clock, which is the only one not
stale when the web view has been frozen in the background.

The tests run against the browser suite's fixture daemon rather than canned
JSON, because the shapes being decoded are the server's and a fixture would
only prove it matches itself. Thirteen pass, including a live scan reported
over SSE and the playback round trip, which still works after the move.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 22:48:14 -04:00

108 lines
3.7 KiB
YAML

# XcodeGen makes the .xcodeproj from this, so the project is something you can read in a diff
# rather than a pbxproj nobody can review.
#
# brew install xcodegen && xcodegen generate && open iPodderX.xcodeproj
name: iPodderX
options:
bundleIdPrefix: net.sdf1
deploymentTarget:
iOS: "16.0"
macOS: "13.0"
createIntermediateGroups: true
settings:
base:
SWIFT_VERSION: "5.9"
TARGETED_DEVICE_FAMILY: "1,2"
CODE_SIGN_STYLE: Automatic
targets:
iPodderX:
type: application
platform: iOS
# The same UIKit app on the Mac. Everything that matters -- Playback, Library, Bridge,
# CookieBridge -- never touches a view, so only the shell is platform-specific.
supportsMacCatalyst: true
sources:
- Sources
- Resources/Assets.xcassets
info:
path: Resources/Info.plist
properties:
CFBundleDisplayName: iPodderX
CFBundleShortVersionString: "0.1.0"
CFBundleVersion: "1"
# Playing on with the screen locked. This is a plist key, not a signed entitlement, so it
# works on a free personal team -- unlike CarPlay, which Apple has to grant.
UIBackgroundModes: [audio]
UILaunchScreen: {}
# Mac idiom rather than a scaled iPad. Without this a Catalyst app draws its iPad
# interface at 77%, which is why everything read small on the Mac.
UIDesignRequiresCompatibility: false
# iOS 27 will not run an app that has not adopted the scene lifecycle. A CarPlay app is a
# second scene beside this one, so its role goes here too when the entitlement exists.
UIApplicationSceneManifest:
UIApplicationSupportsMultipleScenes: false
UISceneConfigurations:
UIWindowSceneSessionRoleApplication:
- UISceneConfigurationName: Default Configuration
UISceneDelegateClassName: $(PRODUCT_MODULE_NAME).SceneDelegate
UIRequiresFullScreen: false
UISupportedInterfaceOrientations:
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
UIStatusBarStyle: UIStatusBarStyleLightContent
# Only needed to point the app at the LAN address, which is plain HTTP. The tunnel is
# HTTPS and needs none of this.
NSAppTransportSecurity:
NSAllowsLocalNetworking: true
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: net.sdf1.ipodderx
MARKETING_VERSION: "0.1.0"
# Set as build settings rather than xcodegen's supportsMacCatalyst:, which this version
# accepts and then writes nothing for -- the generated project had no SUPPORTS_MACCATALYST
# at all and the Mac destination simply did not exist.
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
SUPPORTS_MACCATALYST: "YES"
# Apple Silicon only. The default builds a universal binary, and the x86_64 half is
# weight nothing here will ever run.
ARCHS[sdk=macosx*]: arm64
DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER: "NO"
iPodderXTests:
type: bundle.unit-test
platform: iOS
sources:
- Tests
dependencies:
- target: iPodderX
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: net.sdf1.ipodderx.tests
iPodderXUITests:
type: bundle.ui-testing
platform: iOS
sources:
- UITests
dependencies:
- target: iPodderX
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: net.sdf1.ipodderx.uitests
schemes:
iPodderX:
build:
targets:
iPodderX: all
iPodderXTests: [test]
iPodderXUITests: [test]
run:
config: Debug
test:
config: Debug
targets:
- iPodderXTests
- iPodderXUITests