/** * useCapture — React hook that encapsulates the camera capture state * machine so host apps get a drop-in replacement for the ad-hoc * vision-camera wiring they used to have inline on each screen. * * Responsibilities: * - Holds the Camera ref for ``takePhoto``. * - Tracks the device permission state and exposes a request helper. * - Manages torch / flash state + a toggle helper. * - Wraps takePhoto with a single-flight guard so a double-tap on * the shutter button doesn't spawn two captures in parallel. * - Runs an optional JS-side quality check on the captured image * before resolving; the host app sees the QualityReport on the * returned CaptureResult. * * Non-goals: * - This hook does NOT persist captures. Host apps hand the * returned CaptureResult to their own storage layer (WatermelonDB * insert, Redux dispatch, whatever). * - Video recording lives in useVideoCapture. * * The public API is designed to be minimal and replaceable: host apps * that prefer the raw vision-camera API can opt out of this hook and * still use the SDK's quality + stitching modules. */ import { Camera, useCameraDevice, type PhysicalCameraDeviceType, type TakePhotoOptions } from 'react-native-vision-camera'; import { type CaptureDeviceMode } from './selectCaptureDevice'; import type { CaptureResult, QualityThresholds } from '../types'; /** * Hook input. Everything optional; sensible defaults are applied * so simple call-sites can write ``useCapture()`` and get a usable * back-camera pipeline with ``flash=off`` and no quality checking. */ export interface UseCaptureOptions { /** 'back' | 'front' — defaults to 'back' (shelf photos). */ cameraPosition?: 'back' | 'front'; /** Quality check toggle + thresholds. */ enableQualityChecks?: boolean; qualityThresholds?: QualityThresholds; /** * Extra TakePhotoOptions to pass through to vision-camera. * The SDK merges these with its defaults; host-supplied values win. */ takePhotoOptions?: TakePhotoOptions; /** * 2026-05-14 — preferred physical-lens type for the chosen * `cameraPosition`. Maps to vision-camera's `physicalDevices` * filter on `useCameraDevice`. * * undefined (default) — use vision-camera's selection algorithm, * which picks the device that combines * the most lenses (typically the "main" * multi-lens virtual camera). Existing * behaviour; backwards-compatible. * 'wide-angle-camera' — 1× physical lens (the standard rear * camera most users think of as "the * camera"). * 'ultra-wide-angle-camera' — 0.5× ultra-wide lens (only on * devices with one; Samsung A35 has one; * iPhone 11 Pro and later have one). * 'telephoto-camera' — 2× / 3× telephoto if the device has * one. Rare on field-rep deployments; * exposed for symmetry. * * When the preferred type isn't available on the device, the * hook falls back to vision-camera's default selection (i.e., * behaves as if `preferredPhysicalDevice` was undefined). The * returned `availablePhysicalDevices` exposes what the device * actually offers so the host can render an appropriate switcher. * * v0.13.2 — superseded by `lens` for ``'s own use (see * `selectCaptureDevice`). Still honoured for direct Layer-2 hosts. */ preferredPhysicalDevice?: PhysicalCameraDeviceType; /** * v0.13.2 — the active UI lens (`1×` / `0.5×`). When supplied, the * hook uses capability-aware selection (`selectCaptureDevice`): it * prefers a multi-cam device spanning both FOVs (lens switched via * `zoom`, torch available on every lens), and falls back to a * standalone ultra-wide device-swap only where no such multi-cam * device exists. Fixes the "0.5× shows wide-angle on some phones" * and "flash unavailable on 0.5×" bugs. When omitted, the legacy * `preferredPhysicalDevice` path is used (backwards-compatible). */ lens?: '1x' | '0.5x'; /** * iOS: save the still's AVDepthData as a `.depth.bin` sidecar * (float32 metres + JSON header; see `extractPhotoDepth`) and return its * path as `CaptureResult.depthPath`. Requires the mounted `` * to also set `captureDepthData` (that's what turns on depth delivery and * biases the format pick); this option adds the extraction leg, which * MUST run before the orientation re-encode strips the embedded depth. * Works on dual-camera iPhones (stereo disparity) and LiDAR models * (absolute depth). No-op on Android and on depth-less devices — * `depthPath` is simply absent. Default off. */ captureDepthData?: boolean; } /** * Per-call options for `takePhoto`. Separate from `UseCaptureOptions` * (the hook-level config) so callers can vary the destination * filename per capture without re-creating the hook. */ export interface TakePhotoCallOptions { /** * Move the captured JPEG to this fully-resolved path after EXIF * orientation correction. Requires `expo-file-system` in the * host (declared as an OPTIONAL peer — only needed when * `outputPath` is set). Host is responsible for the destination * directory's existence and writability; lib rejects loudly on * disk failure rather than silently falling back to a tmp path. * * Format: bare path (e.g. `/data/.../foo.jpg`) or `file://`-prefixed * URI — both accepted; lib normalises internally. */ outputPath?: string; } /** * Hook output. Intentionally flat so destructuring a subset is * cheap and the API doesn't force callers to drill into nested * objects for common concerns. */ export interface UseCaptureReturn { /** Pass to (or the raw Camera directly). */ cameraRef: React.RefObject; /** The currently selected device — null while vision-camera hasn't picked one. */ device: ReturnType; /** True once the user has granted camera permission. */ hasPermission: boolean; /** Trigger the system permission sheet. Resolves to the new state. */ requestPermission: () => Promise; /** Current flash mode — controlled from host code. */ flash: 'off' | 'on'; toggleFlash: () => void; /** True while takePhoto is in flight. Use to disable the shutter button. */ isCapturing: boolean; /** * Take a photo. Single-flight: parallel calls return the in-flight * promise. Returns a CaptureResult (with an optional QualityReport * when ``enableQualityChecks`` is on). * * `outputPath` (optional): a fully-resolved destination path. When * set, the lib moves the captured JPEG to that path after EXIF * orientation correction, and the returned `compressedUri` points * at the moved file. The host is responsible for ensuring the * destination directory exists and is writable; on disk failure, * the promise rejects with an error referencing `outputPath`. * * Requires `expo-file-system` to be installed in the host app * (declared as an OPTIONAL peer dep — consumers that don't pass * `outputPath` aren't required to have it). */ takePhoto: (options?: TakePhotoCallOptions) => Promise; /** * 2026-05-14 — physical lens types available on the chosen * `cameraPosition`. Computed once at the first vision-camera * device-list emission; useful for the host to decide whether to * render a 0.5×/1× camera switcher chip (only show if both * `wide-angle-camera` AND `ultra-wide-angle-camera` are present). * * Empty array on platforms that haven't enumerated devices yet * (very brief — vision-camera resolves the device list at module * load). Always populated by the time the camera is mountable. */ availablePhysicalDevices: PhysicalCameraDeviceType[]; /** * v0.13.2 — how lenses are switched for the mounted device: * 'multicam' — one device spans both FOVs; switch via `deviceZoom`. * 'standalone-uw' — separate ultra-wide device; switch by remounting. * 'wide-only' — no ultra-wide; no 0.5× chooser. */ captureMode: CaptureDeviceMode; /** * v0.13.2 — whether the device can offer a 0.5× ultra-wide lens AT ALL * (real capability, replacing the old hardcoded assumption). Drives * whether `` renders the lens chooser. */ has0_5x: boolean; /** * The device's real ultra-wide factor for the lens chip's LABEL (0.6 on a * Galaxy S24 Ultra, 0.5 on a typical iPhone); null when the platform never * advertises it, so the UI keeps its historical `0.5×` text. See * `CaptureDeviceSelection.ultraWideFactor`. */ ultraWideFactor: number | null; /** * v0.13.2 — whether the currently-MOUNTED device has a torch. Drives * the flash control's availability (the standalone ultra-wide has none). */ deviceHasTorch: boolean; /** * v0.13.2 — the `zoom` value to apply for the active lens in * `multicam` mode (0.5× → ultra-wide end, 1× → wide baseline). * `undefined` in standalone/wide-only modes (lens = device identity, * no zoom needed). Pass to ``. */ deviceZoom: number | undefined; } export declare function useCapture(options?: UseCaptureOptions): UseCaptureReturn; //# sourceMappingURL=useCapture.d.ts.map