WIP: Moves camera setting to Settings screen
This commit is contained in:
parent
ede1783ed9
commit
3eef273701
40
App.tsx
40
App.tsx
|
@ -6,17 +6,17 @@ import {BarCodeEvent, BarCodeScanner, PermissionResponse} from 'expo-barcode-sca
|
||||||
import * as firebase from 'firebase';
|
import * as firebase from 'firebase';
|
||||||
import 'firebase/firestore';
|
import 'firebase/firestore';
|
||||||
import React, {ReactElement, useCallback, useEffect, useState} from 'react';
|
import React, {ReactElement, useCallback, useEffect, useState} from 'react';
|
||||||
import {AppRegistry, SafeAreaView, View, YellowBox} from 'react-native';
|
import {AppRegistry, SafeAreaView, Text, View, YellowBox} from 'react-native';
|
||||||
import {
|
import {
|
||||||
Appbar,
|
Appbar,
|
||||||
Button,
|
Button,
|
||||||
DefaultTheme,
|
DefaultTheme,
|
||||||
HelperText,
|
HelperText,
|
||||||
Provider as PaperProvider,
|
Provider as PaperProvider, RadioButton,
|
||||||
Snackbar,
|
Snackbar,
|
||||||
Subheading,
|
Subheading,
|
||||||
TextInput,
|
TextInput,
|
||||||
Title
|
Title,
|
||||||
} from 'react-native-paper';
|
} from 'react-native-paper';
|
||||||
import {expo as appExpo} from './app.json';
|
import {expo as appExpo} from './app.json';
|
||||||
import {CancelButton} from './components/Common';
|
import {CancelButton} from './components/Common';
|
||||||
|
@ -24,7 +24,7 @@ import {BarCodeDisplay, PrintButton, PrintingMessage} from './components/Print';
|
||||||
import {IdNumberInput, InputIdButton, ScanButton, Scanner} from './components/Scan';
|
import {IdNumberInput, InputIdButton, ScanButton, Scanner} from './components/Scan';
|
||||||
import {colors, styles} from './components/Styles';
|
import {colors, styles} from './components/Styles';
|
||||||
import {BarcodeScannerAppState} from './models/BarcodeScannerAppState';
|
import {BarcodeScannerAppState} from './models/BarcodeScannerAppState';
|
||||||
import {ElementProps, StateProps} from './models/ElementProps';
|
import {CameraType, ElementProps, StateProps} from './models/ElementProps';
|
||||||
import {Sample} from './models/Sample';
|
import {Sample} from './models/Sample';
|
||||||
|
|
||||||
const firebaseConfig = {
|
const firebaseConfig = {
|
||||||
|
@ -44,6 +44,7 @@ if (firebase.apps.length === 0) {
|
||||||
|
|
||||||
YellowBox.ignoreWarnings([
|
YellowBox.ignoreWarnings([
|
||||||
'Setting a timer for a long period of time', // Ignore Firebase timer warnings
|
'Setting a timer for a long period of time', // Ignore Firebase timer warnings
|
||||||
|
'Remote debugger is in a background tab', // Ignore Firebase timer warnings
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const db = firebase.firestore();
|
const db = firebase.firestore();
|
||||||
|
@ -62,6 +63,7 @@ export default function Main() {
|
||||||
const [locationStr, setLocationStr] = useState<string>('4321');
|
const [locationStr, setLocationStr] = useState<string>('4321');
|
||||||
const [errorMessage, setErrorMessage] = useState<string>('');
|
const [errorMessage, setErrorMessage] = useState<string>('');
|
||||||
const [samples, setSamples] = useState<Sample[]>([]);
|
const [samples, setSamples] = useState<Sample[]>([]);
|
||||||
|
const [cameraType, setCameraType] = useState<CameraType>('back');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
BarCodeScanner.requestPermissionsAsync().then((value: PermissionResponse) => {
|
BarCodeScanner.requestPermissionsAsync().then((value: PermissionResponse) => {
|
||||||
|
@ -110,6 +112,7 @@ export default function Main() {
|
||||||
// Manually-entered ID numbers will be exactly 9 digits long.
|
// Manually-entered ID numbers will be exactly 9 digits long.
|
||||||
const barCodeString = e.data;
|
const barCodeString = e.data;
|
||||||
const pattern = /^[\d]{14}$|^[\d]{9}$/;
|
const pattern = /^[\d]{14}$|^[\d]{9}$/;
|
||||||
|
console.log('barCodeString', barCodeString);
|
||||||
if (pattern.test(barCodeString)) {
|
if (pattern.test(barCodeString)) {
|
||||||
const cardId = e.data.slice(0, 9);
|
const cardId = e.data.slice(0, 9);
|
||||||
const newSampleDate = new Date();
|
const newSampleDate = new Date();
|
||||||
|
@ -168,13 +171,38 @@ export default function Main() {
|
||||||
|
|
||||||
function SettingsScreen(props: ElementProps): ReactElement {
|
function SettingsScreen(props: ElementProps): ReactElement {
|
||||||
const [inputStr, setInputStr] = useState<string>(locationStr);
|
const [inputStr, setInputStr] = useState<string>(locationStr);
|
||||||
|
|
||||||
const pattern = /^[\d]{4}$/;
|
const pattern = /^[\d]{4}$/;
|
||||||
const hasErrors = () => {
|
const hasErrors = () => {
|
||||||
return !pattern.test(inputStr);
|
return !pattern.test(inputStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
return <View style={styles.settings}>
|
return <View style={styles.settings}>
|
||||||
<Title style={styles.headingInverse}>Settings</Title>
|
<View style={{marginBottom: 10}}>
|
||||||
|
<Subheading style={{color: DefaultTheme.colors.text}}>Which camera to scan bar codes with?</Subheading>
|
||||||
|
<RadioButton.Group
|
||||||
|
onValueChange={value => setCameraType(value as CameraType)}
|
||||||
|
value={cameraType as string}
|
||||||
|
>
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Text>Front</Text>
|
||||||
|
<RadioButton
|
||||||
|
value="front"
|
||||||
|
color={colors.primary}
|
||||||
|
uncheckedColor={colors.accent}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Text>Back</Text>
|
||||||
|
<RadioButton
|
||||||
|
value="back"
|
||||||
|
color={colors.primary}
|
||||||
|
uncheckedColor={colors.accent}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</RadioButton.Group>
|
||||||
|
</View>
|
||||||
|
|
||||||
<View style={{marginBottom: 10}}>
|
<View style={{marginBottom: 10}}>
|
||||||
<Subheading style={{color: DefaultTheme.colors.text, marginBottom: 60}}>
|
<Subheading style={{color: DefaultTheme.colors.text, marginBottom: 60}}>
|
||||||
Please do NOT change this unless you know what you are doing. Entering an incorrect location number may
|
Please do NOT change this unless you know what you are doing. Entering an incorrect location number may
|
||||||
|
@ -264,11 +292,13 @@ export default function Main() {
|
||||||
return <Scanner
|
return <Scanner
|
||||||
onScanned={handleBarCodeScanned}
|
onScanned={handleBarCodeScanned}
|
||||||
onCancel={_home}
|
onCancel={_home}
|
||||||
|
cameraType={cameraType}
|
||||||
/>;
|
/>;
|
||||||
case BarcodeScannerAppState.INPUT:
|
case BarcodeScannerAppState.INPUT:
|
||||||
return <IdNumberInput
|
return <IdNumberInput
|
||||||
onScanned={handleBarCodeScanned}
|
onScanned={handleBarCodeScanned}
|
||||||
onCancel={_home}
|
onCancel={_home}
|
||||||
|
cameraType={undefined}
|
||||||
/>;
|
/>;
|
||||||
case BarcodeScannerAppState.SETTINGS:
|
case BarcodeScannerAppState.SETTINGS:
|
||||||
return <SettingsScreen/>;
|
return <SettingsScreen/>;
|
||||||
|
|
7
app.json
7
app.json
|
@ -4,7 +4,7 @@
|
||||||
"name": "uva-covid19-testing-kiosk",
|
"name": "uva-covid19-testing-kiosk",
|
||||||
"slug": "uva-covid19-testing-kiosk",
|
"slug": "uva-covid19-testing-kiosk",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"orientation": "portrait",
|
"orientation": "landscape",
|
||||||
"icon": "./assets/icon.png",
|
"icon": "./assets/icon.png",
|
||||||
"splash": {
|
"splash": {
|
||||||
"image": "./assets/splash.png",
|
"image": "./assets/splash.png",
|
||||||
|
@ -19,7 +19,8 @@
|
||||||
],
|
],
|
||||||
"ios": {
|
"ios": {
|
||||||
"supportsTablet": true,
|
"supportsTablet": true,
|
||||||
"bundleIdentifier": "com.sartography.uvacovid19testingkiosk"
|
"bundleIdentifier": "com.sartography.uvacovid19testingkiosk",
|
||||||
|
"requireFullScreen": true
|
||||||
},
|
},
|
||||||
"web": {
|
"web": {
|
||||||
"favicon": "./assets/favicon.png"
|
"favicon": "./assets/favicon.png"
|
||||||
|
@ -34,4 +35,4 @@
|
||||||
"package": "com.sartography.uvacovid19testingkiosk"
|
"package": "com.sartography.uvacovid19testingkiosk"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,52 +5,32 @@ import {Button, DefaultTheme, HelperText, Subheading, TextInput, Title} from 're
|
||||||
import {ButtonProps, ScannerProps} from '../models/ElementProps';
|
import {ButtonProps, ScannerProps} from '../models/ElementProps';
|
||||||
import {colors, styles} from './Styles';
|
import {colors, styles} from './Styles';
|
||||||
|
|
||||||
declare type CameraType = number | 'front' | 'back' | undefined;
|
|
||||||
|
|
||||||
export const Scanner = (props: ScannerProps): ReactElement => {
|
export const Scanner = (props: ScannerProps): ReactElement => {
|
||||||
const [componentKey, setComponentKey] = useState<number>(0);
|
return <View style={styles.container}>
|
||||||
const [cameraType, setCameraType] = useState<CameraType>('back');
|
<View style={styles.container}>
|
||||||
|
<BarCodeScanner
|
||||||
const _toggleCameraType = () => {
|
type={props.cameraType}
|
||||||
setCameraType(cameraType === 'front' ? 'back' : 'front');
|
onBarCodeScanned={props.onScanned}
|
||||||
setComponentKey(componentKey + 1);
|
style={styles.fullScreen}
|
||||||
}
|
/>
|
||||||
|
</View>
|
||||||
const ScanCamera = (): ReactElement => {
|
<View style={styles.centerMiddle}>
|
||||||
return <View style={styles.container}>
|
<View style={styles.captureBox}/>
|
||||||
<View style={styles.container}>
|
</View>
|
||||||
<BarCodeScanner
|
<Text style={styles.subtitle}>
|
||||||
type={cameraType}
|
Hold your ID card up, with the barcode facing the camera. Keep the card in the green box.
|
||||||
onBarCodeScanned={props.onScanned}
|
</Text>
|
||||||
style={styles.fullScreen}
|
<View style={styles.centerMiddle}>
|
||||||
/>
|
<Button
|
||||||
</View>
|
mode="text"
|
||||||
<View style={styles.centerMiddle}>
|
color={colors.primary}
|
||||||
<View style={styles.captureBox}/>
|
icon="cancel"
|
||||||
</View>
|
onPress={props.onCancel}
|
||||||
<Text style={styles.subtitle}>
|
style={styles.btnWhite}
|
||||||
Hold your ID card up, with the barcode facing the camera. Keep the card in the green box.
|
>Cancel</Button>
|
||||||
</Text>
|
</View>
|
||||||
<View style={styles.centerMiddle}>
|
</View>;
|
||||||
<Button
|
|
||||||
mode="contained"
|
|
||||||
color={colors.primary}
|
|
||||||
icon="camera-switch"
|
|
||||||
onPress={_toggleCameraType}
|
|
||||||
style={{marginVertical: 10}}
|
|
||||||
>Switch Camera</Button>
|
|
||||||
<Button
|
|
||||||
mode="text"
|
|
||||||
color={colors.primary}
|
|
||||||
icon="cancel"
|
|
||||||
onPress={props.onCancel}
|
|
||||||
style={styles.btnWhite}
|
|
||||||
>Cancel</Button>
|
|
||||||
</View>
|
|
||||||
</View>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <ScanCamera key={componentKey}/>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ScanButton = (props: ButtonProps): ReactElement => {
|
export const ScanButton = (props: ButtonProps): ReactElement => {
|
||||||
|
@ -70,6 +50,7 @@ export const InputIdButton = (props: ButtonProps): ReactElement => {
|
||||||
mode="text"
|
mode="text"
|
||||||
color={colors.onBackground}
|
color={colors.onBackground}
|
||||||
onPress={props.onClicked}
|
onPress={props.onClicked}
|
||||||
|
style={{marginTop: 30}}
|
||||||
>Enter ID Number Manually</Button>;
|
>Enter ID Number Manually</Button>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -85,7 +66,7 @@ export const IdNumberInput = (props: ScannerProps): ReactElement => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return <View style={styles.settings}>
|
return <View style={styles.settings}>
|
||||||
<Title style={styles.headingInverse}>Settings</Title>
|
<Title style={styles.headingInverse}>Manual ID # Entry</Title>
|
||||||
<View style={{marginBottom: 10}}>
|
<View style={{marginBottom: 10}}>
|
||||||
<Subheading style={{color: DefaultTheme.colors.text, marginBottom: 60}}>
|
<Subheading style={{color: DefaultTheme.colors.text, marginBottom: 60}}>
|
||||||
Please double check that you have entered the number correctly. Entering an incorrect ID number will prevent
|
Please double check that you have entered the number correctly. Entering an incorrect ID number will prevent
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import {BarCodeScannedCallback} from 'expo-barcode-scanner';
|
import {BarCodeScannedCallback} from 'expo-barcode-scanner';
|
||||||
import {BarcodeScannerAppState} from './BarcodeScannerAppState';
|
import {BarcodeScannerAppState} from './BarcodeScannerAppState';
|
||||||
|
|
||||||
|
export declare type CameraType = number | 'front' | 'back' | undefined;
|
||||||
|
export declare type CheckedStatus ='checked' | 'unchecked' | undefined;
|
||||||
|
|
||||||
export interface ElementProps {
|
export interface ElementProps {
|
||||||
title?: string;
|
title?: string;
|
||||||
}
|
}
|
||||||
|
@ -23,6 +26,7 @@ export interface ButtonProps extends ElementProps {
|
||||||
export interface ScannerProps extends ElementProps {
|
export interface ScannerProps extends ElementProps {
|
||||||
onScanned: BarCodeScannedCallback;
|
onScanned: BarCodeScannedCallback;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
|
cameraType: CameraType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PrintingProps extends BarCodeProps {
|
export interface PrintingProps extends BarCodeProps {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"expo": "~38.0.8",
|
"expo": "~38.0.8",
|
||||||
"expo-barcode-scanner": "~8.2.1",
|
"expo-barcode-scanner": "~8.2.1",
|
||||||
"expo-print": "~9.0.1",
|
"expo-print": "~9.0.1",
|
||||||
|
"expo-screen-orientation": "~1.1.1",
|
||||||
"expo-splash-screen": "^0.5.0",
|
"expo-splash-screen": "^0.5.0",
|
||||||
"expo-status-bar": "^1.0.2",
|
"expo-status-bar": "^1.0.2",
|
||||||
"expo-updates": "~0.2.10",
|
"expo-updates": "~0.2.10",
|
||||||
|
|
14
yarn.lock
14
yarn.lock
|
@ -4334,6 +4334,13 @@ expo-print@~9.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/expo-print/-/expo-print-9.0.2.tgz#1138bbc0dc94799962980cdc9c09475ba4943d4d"
|
resolved "https://registry.yarnpkg.com/expo-print/-/expo-print-9.0.2.tgz#1138bbc0dc94799962980cdc9c09475ba4943d4d"
|
||||||
integrity sha512-Jk8Q4QOdkCGY4zqr+omLMnsX5FPQYz6Ug2TfUeAixwPfJuNuGUPPvWiQhucxV4idS0C1nHh4HAXj+S27zDZwig==
|
integrity sha512-Jk8Q4QOdkCGY4zqr+omLMnsX5FPQYz6Ug2TfUeAixwPfJuNuGUPPvWiQhucxV4idS0C1nHh4HAXj+S27zDZwig==
|
||||||
|
|
||||||
|
expo-screen-orientation@~1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/expo-screen-orientation/-/expo-screen-orientation-1.1.1.tgz#515776e534530efdb716e56ec0c47cf8fb9de82f"
|
||||||
|
integrity sha512-o3RhmidIhVK4lXHVActnO2iD0ZrZKxzWuRrJaTSpRsvRjCabeE74xkpZWPGcEcXhAxEwMaAAizHO8rlJDdrVzw==
|
||||||
|
dependencies:
|
||||||
|
fbjs "1.0.0"
|
||||||
|
|
||||||
expo-splash-screen@^0.5.0:
|
expo-splash-screen@^0.5.0:
|
||||||
version "0.5.0"
|
version "0.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/expo-splash-screen/-/expo-splash-screen-0.5.0.tgz#cad0eb77a3eade2c7101d169b8655e7ee8053c2f"
|
resolved "https://registry.yarnpkg.com/expo-splash-screen/-/expo-splash-screen-0.5.0.tgz#cad0eb77a3eade2c7101d169b8655e7ee8053c2f"
|
||||||
|
@ -7589,7 +7596,12 @@ q@^1.1.2:
|
||||||
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
|
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
|
||||||
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
|
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
|
||||||
|
|
||||||
qrcode@^1.3.2:
|
qrcode-svg@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/qrcode-svg/-/qrcode-svg-1.1.0.tgz#2087549843dc5d0a3f8e8aa046cd9bcf23708cc3"
|
||||||
|
integrity sha512-XyQCIXux1zEIA3NPb0AeR8UMYvXZzWEhgdBgBjH9gO7M48H9uoHzviNz8pXw3UzrAcxRRRn9gxHewAVK7bn9qw==
|
||||||
|
|
||||||
|
qrcode@^1.3.2, qrcode@^1.4.4:
|
||||||
version "1.4.4"
|
version "1.4.4"
|
||||||
resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.4.4.tgz#f0c43568a7e7510a55efc3b88d9602f71963ea83"
|
resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.4.4.tgz#f0c43568a7e7510a55efc3b88d9602f71963ea83"
|
||||||
integrity sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q==
|
integrity sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q==
|
||||||
|
|
Loading…
Reference in New Issue