// // DeviceCapabilities.swift // Focale // // Author: Simon-Pierre Boucher // Contact: contact@spboucher.ai // // Every hardware capability is queried before a control is exposed // (CLAUDE.md ยง4): no dead buttons, no assumptions about iPhone model. // import Foundation /// Sendable snapshot of what the active capture device supports. struct DeviceCapabilities: Sendable { var availableLenses: [LensKind] var supportsProRAW: Bool var isoRange: ClosedRange var shutterRange: ClosedRange // seconds var exposureBiasRange: ClosedRange // EV var maxWhiteBalanceGain: Float var maxZoomFactor: Double var supportsManualFocus: Bool var hasDepthCapture: Bool // LiDAR / depth for SceneSignal var hasFlash: Bool static let none = DeviceCapabilities( availableLenses: [], supportsProRAW: false, isoRange: 100...100, shutterRange: 0.008...0.008, exposureBiasRange: 0...0, maxWhiteBalanceGain: 1, maxZoomFactor: 1, supportsManualFocus: false, hasDepthCapture: false, hasFlash: false ) func supports(_ control: CaptureControl) -> Bool { switch control { case .iso: isoRange.lowerBound < isoRange.upperBound case .shutterSpeed: shutterRange.lowerBound < shutterRange.upperBound case .exposureBias: exposureBiasRange.lowerBound < exposureBiasRange.upperBound case .focus: supportsManualFocus case .whiteBalance: maxWhiteBalanceGain > 1 case .zoom: maxZoomFactor > 1 } } }