| 
						 
							
							
							
						 
					 | 
				
			
			 | 
			 | 
			
				@@ -1,12 +1,9 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import * as React from 'react'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import { useRef, useState, useCallback } from 'react'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import { useState } from 'react'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import { StyleSheet, View } from 'react-native'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import { PinchGestureHandler, PinchGestureHandlerGestureEvent, TapGestureHandler } from 'react-native-gesture-handler'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import { CameraRuntimeError, useCameraDevice, useCameraFormat, useCodeScanner } from 'react-native-vision-camera'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import { useCameraDevice, useCodeScanner } from 'react-native-vision-camera'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import { Camera } from 'react-native-vision-camera'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import { CONTENT_SPACING, MAX_ZOOM_FACTOR, SAFE_AREA_PADDING, SCREEN_HEIGHT, SCREEN_WIDTH } from './Constants'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import Reanimated, { Extrapolate, interpolate, useAnimatedGestureHandler, useAnimatedProps, useSharedValue } from 'react-native-reanimated'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import { useEffect } from 'react'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import { CONTENT_SPACING, CONTROL_BUTTON_SIZE, SAFE_AREA_PADDING } from './Constants'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import { useIsForeground } from './hooks/useIsForeground'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import { StatusBarBlurBackground } from './views/StatusBarBlurBackground'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import { PressableOpacity } from 'react-native-pressable-opacity'
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -14,130 +11,23 @@ import IonIcon from 'react-native-vector-icons/Ionicons'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import type { Routes } from './Routes'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import type { NativeStackScreenProps } from '@react-navigation/native-stack'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import { useIsFocused } from '@react-navigation/core'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import { usePreferredCameraDevice } from './hooks/usePreferredCameraDevice'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				const ReanimatedCamera = Reanimated.createAnimatedComponent(Camera)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				Reanimated.addWhitelistedNativeProps({
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  zoom: true,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				})
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				const SCALE_FULL_ZOOM = 3
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				const BUTTON_SIZE = 40
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				type Props = NativeStackScreenProps<Routes, 'CodeScannerPage'>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				export function CodeScannerPage({ navigation }: Props): React.ReactElement {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const camera = useRef<Camera>(null)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const [isCameraInitialized, setIsCameraInitialized] = useState(false)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const zoom = useSharedValue(0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const isPressingButton = useSharedValue(false)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // 1. Use a simple default back camera
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const device = useCameraDevice('back')
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // check if camera page is active
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const isFocussed = useIsFocused()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // 2. Only activate Camera when the app is focused and this screen is currently opened
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const isFocused = useIsFocused()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const isForeground = useIsForeground()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const isActive = isFocussed && isForeground
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const isActive = isFocused && isForeground
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const [cameraPosition, setCameraPosition] = useState<'front' | 'back'>('back')
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const [enableHdr, setEnableHdr] = useState(false)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const [torch, setTorch] = useState<'off' | 'on'>('off')
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const [enableNightMode, setEnableNightMode] = useState(false)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // camera device settings
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const [preferredDevice] = usePreferredCameraDevice()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  let device = useCameraDevice(cameraPosition)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (preferredDevice != null && preferredDevice.position === cameraPosition) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // override default device with the one selected by the user in settings
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    device = preferredDevice
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const [targetFps, setTargetFps] = useState(60)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const screenAspectRatio = SCREEN_HEIGHT / SCREEN_WIDTH
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const format = useCameraFormat(device, [
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { fps: targetFps },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { videoAspectRatio: screenAspectRatio },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { videoResolution: 'max' },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { photoAspectRatio: screenAspectRatio },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { photoResolution: 'max' },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  ])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const fps = Math.min(format?.maxFps ?? 1, targetFps)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const supportsTorch = device?.hasTorch ?? false
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  //#region Animated Zoom
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // This just maps the zoom factor to a percentage value.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // so e.g. for [min, neutr., max] values [1, 2, 128] this would result in [0, 0.0081, 1]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const minZoom = device?.minZoom ?? 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const maxZoom = Math.min(device?.maxZoom ?? 1, MAX_ZOOM_FACTOR)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const cameraAnimatedProps = useAnimatedProps(() => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const z = Math.max(Math.min(zoom.value, maxZoom), minZoom)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      zoom: z,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }, [maxZoom, minZoom, zoom])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  //#endregion
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  //#region Callbacks
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // Camera callbacks
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const onError = useCallback((error: CameraRuntimeError) => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    console.error(error)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }, [])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const onInitialized = useCallback(() => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    console.log('Camera initialized!')
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    setIsCameraInitialized(true)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }, [])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const onFlipCameraPressed = useCallback(() => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    setCameraPosition((p) => (p === 'back' ? 'front' : 'back'))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }, [])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const onTorchPressed = useCallback(() => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    setTorch((f) => (f === 'off' ? 'on' : 'off'))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }, [])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  //#endregion
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  //#region Tap Gesture
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const onDoubleTap = useCallback(() => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    onFlipCameraPressed()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }, [onFlipCameraPressed])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  //#endregion
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  //#region Effects
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const neutralZoom = device?.neutralZoom ?? 1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  useEffect(() => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Run everytime the neutralZoomScaled value changes. (reset zoom when device changes)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    zoom.value = neutralZoom
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }, [neutralZoom, zoom])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  //#endregion
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  //#region Pinch to Zoom Gesture
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // The gesture handler maps the linear pinch gesture (0 - 1) to an exponential curve since a camera's zoom
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // function does not appear linear to the user. (aka zoom 0.1 -> 0.2 does not look equal in difference as 0.8 -> 0.9)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const onPinchGesture = useAnimatedGestureHandler<PinchGestureHandlerGestureEvent, { startZoom?: number }>({
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    onStart: (_, context) => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      context.startZoom = zoom.value
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    onActive: (event, context) => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      // we're trying to map the scale gesture to a linear zoom here
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      const startZoom = context.startZoom ?? 0
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      const scale = interpolate(event.scale, [1 - 1 / SCALE_FULL_ZOOM, 1, SCALE_FULL_ZOOM], [-1, 0, 1], Extrapolate.CLAMP)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      zoom.value = interpolate(scale, [-1, 0, 1], [minZoom, startZoom, maxZoom], Extrapolate.CLAMP)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  })
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  //#endregion
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  useEffect(() => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const f =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      format != null
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ? `(${format.photoWidth}x${format.photoHeight} photo / ${format.videoWidth}x${format.videoHeight}@${format.maxFps} video @ ${fps}fps)`
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        : undefined
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    console.log(`Camera: ${device?.name} | Format: ${f}`)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }, [device?.name, format, fps])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // 3. (Optional) enable a torch setting
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const [torch, setTorch] = useState(false)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // 4. Initialize the Code Scanner to scan QR codes and Barcodes
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const codeScanner = useCodeScanner({
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    codeTypes: ['qr'],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    codeTypes: ['qr', 'ean-13'],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    onCodeScanned: (codes, frame) => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      console.log(codes, frame)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    },
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -146,50 +36,27 @@ export function CodeScannerPage({ navigation }: Props): React.ReactElement {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  return (
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    <View style={styles.container}>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      {device != null && (
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        <PinchGestureHandler onGestureEvent={onPinchGesture} enabled={isActive}>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          <Reanimated.View style={StyleSheet.absoluteFill}>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            <TapGestureHandler onEnded={onDoubleTap} numberOfTaps={2}>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              <ReanimatedCamera
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                ref={camera}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                style={StyleSheet.absoluteFill}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                device={device}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                format={format}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                fps={fps}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                hdr={enableHdr}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                torch={supportsTorch ? torch : 'off'}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                lowLightBoost={device.supportsLowLightBoost && enableNightMode}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                isActive={isActive}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                onInitialized={onInitialized}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                onError={onError}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                enableZoomGesture={false}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                animatedProps={cameraAnimatedProps}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                enableFpsGraph={true}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                orientation="portrait"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                codeScanner={codeScanner}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              />
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            </TapGestureHandler>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          </Reanimated.View>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        </PinchGestureHandler>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        <Camera
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          style={StyleSheet.absoluteFill}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          device={device}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          isActive={isActive}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          codeScanner={codeScanner}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          torch={torch ? 'on' : 'off'}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        />
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      )}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      <StatusBarBlurBackground />
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      <View style={styles.rightButtonRow}>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        <PressableOpacity style={styles.button} onPress={onFlipCameraPressed} disabledOpacity={0.4}>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          <IonIcon name="camera-reverse" color="white" size={24} />
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        </PressableOpacity>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        {torch && (
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          <PressableOpacity style={styles.button} onPress={onTorchPressed} disabledOpacity={0.4}>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            <IonIcon name={torch === 'on' ? 'flash' : 'flash-off'} color="white" size={24} />
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          </PressableOpacity>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        )}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        <PressableOpacity style={styles.button} onPress={() => navigation.navigate('CameraPage')}>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          <IonIcon name="videocam" color="white" size={24} />
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        </PressableOpacity>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        <PressableOpacity style={styles.button} onPress={() => navigation.navigate('Devices')}>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          <IonIcon name="settings-outline" color="white" size={24} />
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        <PressableOpacity style={styles.button} onPress={() => setTorch(!torch)} disabledOpacity={0.4}>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          <IonIcon name={torch ? 'flash' : 'flash-off'} color="white" size={24} />
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        </PressableOpacity>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      </View>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      {/* Back Button */}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      <PressableOpacity style={styles.backButton} onPress={navigation.goBack}>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        <IonIcon name="chevron-back" size={35} color="black" />
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      </PressableOpacity>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    </View>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  )
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -201,9 +68,9 @@ const styles = StyleSheet.create({
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  button: {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    marginBottom: CONTENT_SPACING,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    width: BUTTON_SIZE,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    height: BUTTON_SIZE,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    borderRadius: BUTTON_SIZE / 2,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    width: CONTROL_BUTTON_SIZE,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    height: CONTROL_BUTTON_SIZE,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    borderRadius: CONTROL_BUTTON_SIZE / 2,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    backgroundColor: 'rgba(140, 140, 140, 0.3)',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    justifyContent: 'center',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    alignItems: 'center',
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -213,10 +80,9 @@ const styles = StyleSheet.create({
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    right: SAFE_AREA_PADDING.paddingRight,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    top: SAFE_AREA_PADDING.paddingTop,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  text: {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    color: 'white',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    fontSize: 11,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    fontWeight: 'bold',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    textAlign: 'center',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  backButton: {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    position: 'absolute',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    left: SAFE_AREA_PADDING.paddingLeft + CONTENT_SPACING,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    top: SAFE_AREA_PADDING.paddingTop + CONTENT_SPACING,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				})
 | 
			
		
		
	
	
		
			
				
					
					| 
						 
							
							
							
						 
					 | 
				
			
			 | 
			 | 
			
				 
 |