From 530ae84792a22ef4b0a355286d4beefad2031c31 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Fri, 14 Mar 2025 09:50:02 -0700 Subject: default to back camera for ios, remember camera --- src/lib/store.ts | 1 + src/routes/(app)/scan/+page.svelte | 86 ++++++++++++++++++++++---------------- 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/src/lib/store.ts b/src/lib/store.ts index 9b57b05d..c7dc9970 100644 --- a/src/lib/store.ts +++ b/src/lib/store.ts @@ -64,6 +64,7 @@ export const passwordPrompt = writable(); export const eventToSign = writable(); export const pubkey = persistLocal("pubkey"); export const signer = persistLocal("signer"); +export const camera = persistLocal("camera"); export const selectSigner = writable(); export const pin = persistLocal("pin"); export const rate = writable(); diff --git a/src/routes/(app)/scan/+page.svelte b/src/routes/(app)/scan/+page.svelte index aab7bcaa..80047487 100644 --- a/src/routes/(app)/scan/+page.svelte +++ b/src/routes/(app)/scan/+page.svelte @@ -3,6 +3,7 @@ import { goto } from "$app/navigation"; import { onMount, onDestroy } from "svelte"; import { BarcodeDetector } from "barcode-detector/ponyfill"; + import { camera } from "$lib/store"; let resize = () => { if (resizing) clearTimeout(resizing); @@ -14,7 +15,6 @@ let barcodeDetector; let scanningFrameId; let cameras = []; - let selectedCamera = ""; let detectionResult = null; // will hold the detected QR code value // Enumerate available video input devices @@ -22,20 +22,36 @@ try { const devices = await navigator.mediaDevices.enumerateDevices(); cameras = devices.filter((device) => device.kind === "videoinput"); - if (!selectedCamera && cameras.length > 0) { - // Prefer a rear-facing camera if available - const envCamera = cameras.find( - (camera) => - camera.label.toLowerCase().includes("back") || - camera.label.toLowerCase().includes("env"), - ); - selectedCamera = envCamera ? envCamera.deviceId : cameras[0].deviceId; + + // Check if we're on an iOS device + const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent); + + if (!$camera && cameras.length > 0) { + if (isIOS) { + // Prefer a camera labeled "back camera" (without additional qualifiers) + const backCamera = cameras.find( + (camera) => + camera.label.toLowerCase().includes("back") && + !camera.label.toLowerCase().includes("dual") && + !camera.label.toLowerCase().includes("wide"), + ); + $camera = backCamera + ? backCamera.deviceId + : cameras[0].deviceId; + } else { + // For non-iOS, default to a camera with the environment facing mode + const envCamera = cameras.find( + (camera) => + camera.label.toLowerCase().includes("back") || + camera.label.toLowerCase().includes("env"), + ); + $camera = envCamera ? envCamera.deviceId : cameras[0].deviceId; + } } } catch (err) { console.error("Error enumerating devices:", err); } } - // Start the camera stream for a given deviceId async function startCamera(deviceId) { stopCameraStream(); @@ -106,8 +122,8 @@ // Handle change of camera selection async function onCameraChange(event) { - selectedCamera = event.target.value; - await startCamera(selectedCamera); + $camera = event.target.value; + await startCamera($camera); videoEl.addEventListener("loadeddata", () => { canvasEl.width = videoEl.videoWidth; canvasEl.height = videoEl.videoHeight; @@ -118,7 +134,7 @@ // Provide a way to restart scanning async function restart() { detectionResult = null; - await startCamera(selectedCamera); + await startCamera($camera); videoEl.addEventListener("loadeddata", () => { canvasEl.width = videoEl.videoWidth; canvasEl.height = videoEl.videoHeight; @@ -129,7 +145,7 @@ let initialize = async () => { barcodeDetector = new BarcodeDetector({ formats: ["qr_code"] }); await getCameraDevices(); - await startCamera(selectedCamera); + await startCamera($camera); videoEl.addEventListener("loadeddata", () => { canvasEl.width = videoEl.videoWidth; canvasEl.height = videoEl.videoHeight; @@ -146,27 +162,27 @@
- - -
- -
-
- -
+ + +
+ +
+
+ +
-- cgit v1.2.3