added qr scaning and finishing touches
This commit is contained in:
parent
bc347c3f05
commit
2cf7f5dc7b
19
app.json
19
app.json
@ -9,7 +9,11 @@
|
||||
"userInterfaceStyle": "automatic",
|
||||
"newArchEnabled": true,
|
||||
"ios": {
|
||||
"supportsTablet": true
|
||||
"supportsTablet": true,
|
||||
"infoPlist": {
|
||||
"NSCameraUsageDescription": "$(PRODUCT_NAME) needs access to your Camera."
|
||||
},
|
||||
"bundleIdentifier": "com.anonymous.ai-questions-app"
|
||||
},
|
||||
"android": {
|
||||
"adaptiveIcon": {
|
||||
@ -19,7 +23,9 @@
|
||||
"monochromeImage": "./assets/images/android-icon-monochrome.png"
|
||||
},
|
||||
"edgeToEdgeEnabled": true,
|
||||
"predictiveBackGestureEnabled": false
|
||||
"predictiveBackGestureEnabled": false,
|
||||
"permissions": ["android.permission.CAMERA"],
|
||||
"package": "com.anonymous.ai_questions_app"
|
||||
},
|
||||
"web": {
|
||||
"output": "static",
|
||||
@ -39,7 +45,14 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"expo-secure-store"
|
||||
"expo-secure-store",
|
||||
[
|
||||
"react-native-vision-camera",
|
||||
{
|
||||
"cameraPermissionText": "$(PRODUCT_NAME) needs access to your Camera.",
|
||||
"enableCodeScanner": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"experiments": {
|
||||
"typedRoutes": true,
|
||||
|
||||
@ -49,7 +49,7 @@ export default function TestsScreen() {
|
||||
selectedValue={category ? `${category}` : undefined}
|
||||
onValueChange={handleChangeCategory}
|
||||
placeholder="Select category" />
|
||||
<Button>
|
||||
<Button onPress={() => router.push('/qr')}>
|
||||
<ButtonText><FontAwesome5 name="qrcode" size={18} /></ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
104
app/qr.tsx
Normal file
104
app/qr.tsx
Normal file
@ -0,0 +1,104 @@
|
||||
import { useStartTestMutation } from "@/api/userTests";
|
||||
import { Button, ButtonText } from "@/components/ui/button";
|
||||
import { ThemedText } from "@/components/ui/themed-text";
|
||||
import getErrorAxiosMessage from "@/utils/get-error-axios-message";
|
||||
import { router, Stack, useFocusEffect } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
import { StyleSheet, Text, View } from "react-native";
|
||||
import { useToast } from "react-native-toast-notifications";
|
||||
import {
|
||||
Camera,
|
||||
useCameraDevice,
|
||||
useCameraPermission,
|
||||
useCodeScanner,
|
||||
} from "react-native-vision-camera";
|
||||
|
||||
const QrScreen = () => {
|
||||
const device = useCameraDevice("back");
|
||||
const { hasPermission, requestPermission } = useCameraPermission();
|
||||
const toast = useToast();
|
||||
const [scanned, setScanned] = useState(false);
|
||||
|
||||
const { mutate, isPending } = useStartTestMutation();
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
setScanned(false);
|
||||
}, [])
|
||||
);
|
||||
|
||||
const handleStartTest = (id: number) => {
|
||||
mutate(
|
||||
{
|
||||
test_id: id,
|
||||
},
|
||||
{
|
||||
onSuccess: (data) => {
|
||||
router.push(`/user-tests/doing/${data.id}`);
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.show(getErrorAxiosMessage(error), { type: "danger" });
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const codeScanner = useCodeScanner({
|
||||
codeTypes: ["qr", "ean-13"],
|
||||
onCodeScanned: (codes) => {
|
||||
if (scanned) return;
|
||||
if (!codes || codes.length === 0) return;
|
||||
|
||||
const scannedValue = codes[0].value;
|
||||
if (scannedValue) {
|
||||
const id = parseInt(scannedValue, 10);
|
||||
setScanned(true);
|
||||
toast.show("Going to test", { type: "normal" });
|
||||
router.push(`/tests/${id}`);
|
||||
// handleStartTest(id);
|
||||
} else {
|
||||
toast.show("Invalid QR code", { type: "warning" });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
if (!hasPermission) {
|
||||
return (
|
||||
<View style={styles.center}>
|
||||
<Stack.Screen options={{ title: "Scan QR Code" }} />
|
||||
<ThemedText>No camera permission</ThemedText>
|
||||
<Button onPress={requestPermission} className="mt-2">
|
||||
<ButtonText>Grant Permission</ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
if (!device) {
|
||||
return (
|
||||
<View style={styles.center}>
|
||||
<ThemedText>No camera device found</ThemedText>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Stack.Screen options={{ title: "Scan QR Code" }} />
|
||||
<Camera
|
||||
codeScanner={codeScanner}
|
||||
style={StyleSheet.absoluteFill}
|
||||
device={device}
|
||||
isActive={true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
center: {
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
});
|
||||
|
||||
export default QrScreen;
|
||||
@ -252,7 +252,7 @@ const DoingUserTestScreen = () => {
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: "flex-start",
|
||||
width: "100%"
|
||||
},
|
||||
top: {
|
||||
width: "100%",
|
||||
|
||||
@ -106,7 +106,7 @@ const Answer = ({
|
||||
{isTextType ? (
|
||||
<FontAwesome5 name="quote-left" />
|
||||
) : (
|
||||
<ThemedText darkColor="#fff" lightColor="#fff">
|
||||
<ThemedText darkColor="#000" lightColor="#fff">
|
||||
{answer.id}
|
||||
</ThemedText>
|
||||
)}
|
||||
|
||||
@ -33,12 +33,13 @@ const CustomSelect = ({
|
||||
return options;
|
||||
}, [options, noneOption]);
|
||||
const backgroundColor = useThemeColor({ }, "background");
|
||||
const metaColor = useThemeColor({}, "meta");
|
||||
|
||||
return (
|
||||
<Select className={className} onValueChange={onValueChange} selectedValue={selectedValue} defaultValue={defaultValue}>
|
||||
<SelectTrigger className="justify-between" variant="outline" size="md" style={{ backgroundColor }}>
|
||||
<SelectInput placeholder={placeholder} />
|
||||
<FontAwesome5 className="mr-3" name="chevron-down" />
|
||||
<FontAwesome5 style={{color: metaColor}} className="mr-3" name="chevron-down" />
|
||||
</SelectTrigger>
|
||||
<SelectPortal>
|
||||
<SelectBackdrop />
|
||||
|
||||
25
package-lock.json
generated
25
package-lock.json
generated
@ -47,6 +47,7 @@
|
||||
"react-native-svg": "^15.15.1",
|
||||
"react-native-toast-notifications": "^3.4.0",
|
||||
"react-native-vector-icons": "^10.3.0",
|
||||
"react-native-vision-camera": "^4.7.3",
|
||||
"react-native-web": "~0.21.0",
|
||||
"react-native-worklets": "^0.5.2",
|
||||
"react-stately": "^3.43.0",
|
||||
@ -14687,6 +14688,30 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-vision-camera": {
|
||||
"version": "4.7.3",
|
||||
"resolved": "https://registry.npmjs.org/react-native-vision-camera/-/react-native-vision-camera-4.7.3.tgz",
|
||||
"integrity": "sha512-g1/neOyjSqn1kaAa2FxI/qp5KzNvPcF0bnQw6NntfbxH6tm0+8WFZszlgb5OV+iYlB6lFUztCbDtyz5IpL47OA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@shopify/react-native-skia": "*",
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-reanimated": "*",
|
||||
"react-native-worklets-core": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@shopify/react-native-skia": {
|
||||
"optional": true
|
||||
},
|
||||
"react-native-reanimated": {
|
||||
"optional": true
|
||||
},
|
||||
"react-native-worklets-core": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-web": {
|
||||
"version": "0.21.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz",
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
"scripts": {
|
||||
"start": "expo start",
|
||||
"reset-project": "node ./scripts/reset-project.js",
|
||||
"android": "expo start --android",
|
||||
"ios": "expo start --ios",
|
||||
"android": "expo run:android",
|
||||
"ios": "expo run:ios",
|
||||
"web": "expo start --web",
|
||||
"lint": "expo lint"
|
||||
},
|
||||
@ -50,6 +50,7 @@
|
||||
"react-native-svg": "^15.15.1",
|
||||
"react-native-toast-notifications": "^3.4.0",
|
||||
"react-native-vector-icons": "^10.3.0",
|
||||
"react-native-vision-camera": "^4.7.3",
|
||||
"react-native-web": "~0.21.0",
|
||||
"react-native-worklets": "^0.5.2",
|
||||
"react-stately": "^3.43.0",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user