6989a98d75
- Arkitektur: docs/auth/passwordless-architecture.md - Backend: iom/quixzoom-auth-service/ (FastAPI + Redis) - Webb: quixzoom-market-pages/se/login/ (QR-kod + polling) - App: iom/quixzoom-app/src/features/auth/ (push + deep links) Flöde: QR-kod → app-godkännande → webb-inloggad
108 lines
2.4 KiB
JavaScript
108 lines
2.4 KiB
JavaScript
/**
|
|
* useCamera Hook
|
|
* React hook for camera operations
|
|
*/
|
|
|
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
import { Camera, useCameraDevices } from 'react-native-vision-camera';
|
|
|
|
export function useCamera() {
|
|
const [hasPermission, setHasPermission] = useState(false);
|
|
const [isActive, setIsActive] = useState(true);
|
|
const [flashMode, setFlashMode] = useState('auto');
|
|
const [zoom, setZoom] = useState(0);
|
|
const [isCapturing, setIsCapturing] = useState(false);
|
|
|
|
const cameraRef = useRef(null);
|
|
const devices = useCameraDevices();
|
|
const device = devices.back;
|
|
|
|
// Check permission on mount
|
|
useEffect(() => {
|
|
checkPermission();
|
|
}, []);
|
|
|
|
const checkPermission = async () => {
|
|
const status = await Camera.requestCameraPermission();
|
|
setHasPermission(status === 'authorized');
|
|
};
|
|
|
|
/**
|
|
* Capture photo
|
|
*/
|
|
const capturePhoto = useCallback(async (options = {}) => {
|
|
if (!cameraRef.current || isCapturing) {
|
|
throw new Error('Camera not ready');
|
|
}
|
|
|
|
setIsCapturing(true);
|
|
|
|
try {
|
|
const photo = await cameraRef.current.takePhoto({
|
|
qualityPrioritization: options.quality || 'quality',
|
|
flash: options.flash || flashMode,
|
|
enableShutterSound: options.shutterSound !== false,
|
|
});
|
|
|
|
return {
|
|
path: photo.path,
|
|
width: photo.width,
|
|
height: photo.height,
|
|
timestamp: new Date().toISOString(),
|
|
};
|
|
} catch (error) {
|
|
console.error('Capture failed:', error);
|
|
throw error;
|
|
} finally {
|
|
setIsCapturing(false);
|
|
}
|
|
}, [flashMode, isCapturing]);
|
|
|
|
/**
|
|
* Toggle flash mode
|
|
*/
|
|
const toggleFlash = useCallback(() => {
|
|
setFlashMode(prev => {
|
|
const modes = ['off', 'auto', 'on'];
|
|
const currentIndex = modes.indexOf(prev);
|
|
return modes[(currentIndex + 1) % modes.length];
|
|
});
|
|
}, []);
|
|
|
|
/**
|
|
* Set zoom level
|
|
*/
|
|
const setZoomLevel = useCallback((level) => {
|
|
setZoom(Math.max(0, Math.min(1, level)));
|
|
}, []);
|
|
|
|
/**
|
|
* Focus on point
|
|
*/
|
|
const focus = useCallback(async (point) => {
|
|
if (cameraRef.current) {
|
|
await cameraRef.current.focus(point);
|
|
}
|
|
}, []);
|
|
|
|
return {
|
|
// Refs
|
|
cameraRef,
|
|
|
|
// State
|
|
hasPermission,
|
|
isActive,
|
|
flashMode,
|
|
zoom,
|
|
isCapturing,
|
|
device,
|
|
|
|
// Actions
|
|
capturePhoto,
|
|
toggleFlash,
|
|
setZoomLevel,
|
|
focus,
|
|
setIsActive,
|
|
};
|
|
}
|