Skip to content
Signal

Platforms

iPhone Duo readiness

What the app needs for iPhone Duo.

Every item of Apple's Preparing your app for iPhone Duo, checked against 82560e7. Deployment target is iOS 17.2, so each iOS 27 API is gated with #available.

API availability

iOSSwiftUIUIKit
26.0backgroundExtensionEffect()UIBackgroundExtensionView
27.0presentationPlacement(_:), topBarPinnedTrailing, visibilityPriority(_:), ToolbarOverflowMenupreferredPlacement, pinnedTrailingGroup, additionalOverflowItems
27.1 (beta)ArrangementView, reservedRegions(kind:options:layoutDirectionBehavior:), toolbarVerticalBehavior(_:), toolbarVerticalEdge, axisBehavior(_:)UIView.reservedRegions(kind:options:), UIArrangementViewController, preferredVerticalBarBehavior, verticalBarEdge
SimulatoriPhone Duo Simulator in Xcode 27.1 beta. StandBy and most app extensions are unavailable there.

Map tab on both displays

Nearby tab bar → vertical bar (system) panel pinned to safe-area left/right
Outer displayThe native tab bar moves to the side. FloatingPanel's default layout pins the surface to the safe area's left and right edges, so it should clear the bar. Verify (G8). Schematic only: no published point size.
Nearby fold today: panel spans the fold
Inner display todayThe tab bar stays on the side in landscape. The panel is a custom view, so the system doesn't move it for the fold, and its cards run across the hinge (G3).
Nearby secondary: Map primary: panel content
Partially folded (proposal)When a .division is active, use an overlay ArrangementView, or keep the panel within one region (G3).

Checklist

Apple itemApple ruleApp today (82560e7)StatusFix
Build and test
Latest XcodeXcode 26 builds don't extend under the status bar and cameraxcode-version: '26.0' (.github/workflows/testflight.yml:51)GapBuild with Xcode 27, then 27.1. G1
Simulator and deviceBoth displays: closed, open and partially folded, rotated in each poseNot runGapRun the test plan. G8
Layout and resizing
System containersPrefer split views, tab bars, arrangement views and navigation stacksNative TabView and NavigationStack per tab. The Map panel is a third-party custom container (views/MapView.swift:389-406).PartlyThe panel needs its own fold handling. G3
Container-relative sizesNot fixed iPhone dimensionsFixed 172 / 128 card columns (views/StopCardView.swift:225, 230), 82 pt time columns (views/StopView.swift:1145, 1192, 1200), 136 pt direction control (:388)GapUse flexible or container-relative widths. Keep ViewThatFits. G7
Scene and container boundsNot screen dimensionsNo UIScreen. Panel anchors are relative to the safe area. The map uses GeometryReader (views/MapView.swift:489, 506-508).Compliant—
Size classesTrack horizontalSizeClass and verticalSizeClassNot read. FloatingPanel re-lays out on size-class change, but we pass one layout.GapUse a regular-width panel layout. G3 / G7
No idiom or orientation logicDon't lay out from userInterfaceIdiom or orientationNone. Portrait-only plist (Config/chitransit-app-Info.plist:58-61).VerifyVerify the inner display. Allow landscape. G7
Bars presented vertically
toolbar(content:) on a NavigationStackUse container bars, not custom barsHome and Search use NavigationStack toolbars. The Map panel has no bar.Compliant—
Tab bar on the sideThe system moves tab bars to the sideNative TabView, visible on every screen including the pushed stop detail.Compliant—
Custom panel and the vertical barRead toolbarVerticalEdge if neededFloatingPanel's default prepareLayout pins the surface to the safe-area left and right. Not overridden.VerifyVerify on the outer display. G8
toolbarVerticalBehavior(_:)Sheet bars are vertical on the outer display by defaultNot set (.automatic). The Settings sheet has a bar.Compliant—
presentationPlacement(_:)Inner-display sheet: center, leading or trailingNo native stop sheet. The pushed stop detail uses the Map panel’s FloatingPanel.n/aCovered by the panel layout. G3
backgroundExtensionEffect()Extend hero images under a vertical barLive map, bottom safe area ignored (views/MapView.swift:505)VerifyThe map must draw under the side bar. Don't mirror a live map. G8
Organizing bar items
Back / Close at the topCustom Back or Close uses .cancellationActionCustom Back at .topBarLeading (views/StopView.swift:77). Panel X is in content.Gap.cancellationAction. G6
Semantic placementsToolbarItemPlacement groupsSettings .topBarTrailing. Done .confirmationAction.Compliant—
topBarPinnedTrailingProminent Done (iOS 27)Done is .confirmationActionCompliantOptional
axisBehavior · visibilityPriorityAxis inclusion and overflow orderAt most two items per barn/a—
ToolbarOverflowMenuUse the system overflowNo custom overflow menuCompliant—
Icon + titleTitle-only or custom-view items aren't verticalSettings and Back are Labels. Done is text-only. The .principal title is custom.GapButton("Done", systemImage: "checkmark"). G6
Arrangement views
ArrangementViewOverlay: primary trailing or bottom, secondary leading or top, when a division is activeMap + panel is already an overlay layout, but a custom oneEvaluatePrototype: panel content primary, Map secondary, iOS 27.1, at the Map tab root. G3
PlacementNot inside a scroll view, list or split view—n/aMap tab root only
Reserved regions
Custom panelUIView.reservedRegions(kind:options:): divisions and occlusions, active or inactiveNot read. A full-width bottom panel spans the fold.GapOn an active .division, keep the surface in one region. G3
Panel headerAvoid occlusions (inner camera while active)Nearby title and X at the top of the surfaceVerifyPad from .occlusion regions. G8
Map focusKeep content out of divisionsThe focused stop is centred above the panel (views/MapView.swift:504, 616-621)GapPad around an active .division. G4
Map controlsFramework views adaptSystem .mapControls onlyCompliant—
Camera
CaptureAVKit and AVFoundation display changesNo capturen/a—

Test plan

SurfaceClosedOpenPartially foldedRotatedCheck
Tab bar (Home, Map, Search)✓✓✓✓On the side when vertical. Search role kept.
Map panel: tip, half, full · Nearby and station✓✓✓✓Clears the vertical bar, never spans the fold, and VoiceOver changes the anchor.
Map focus and pins✓✓✓✓Selected stop never in the fold or under the panel. Map draws under the side bar.
Pushed stop detail (panel above the tab bar)✓✓✓✓Panel clears the vertical bar and the fold, anchors, Back position, tab bar visible.
Settings sheet, alerts, confirmation dialog✓✓✓—Done reachable on every axis. Moved off the fold.
Open or close mid-taskSearch with the keyboard up. Station at full. Panel at tip.State is preserved.
Widgets, Live Activity, StandBy✓✓——Device only.