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",
|
"userInterfaceStyle": "automatic",
|
||||||
"newArchEnabled": true,
|
"newArchEnabled": true,
|
||||||
"ios": {
|
"ios": {
|
||||||
"supportsTablet": true
|
"supportsTablet": true,
|
||||||
|
"infoPlist": {
|
||||||
|
"NSCameraUsageDescription": "$(PRODUCT_NAME) needs access to your Camera."
|
||||||
|
},
|
||||||
|
"bundleIdentifier": "com.anonymous.ai-questions-app"
|
||||||
},
|
},
|
||||||
"android": {
|
"android": {
|
||||||
"adaptiveIcon": {
|
"adaptiveIcon": {
|
||||||
@ -19,7 +23,9 @@
|
|||||||
"monochromeImage": "./assets/images/android-icon-monochrome.png"
|
"monochromeImage": "./assets/images/android-icon-monochrome.png"
|
||||||
},
|
},
|
||||||
"edgeToEdgeEnabled": true,
|
"edgeToEdgeEnabled": true,
|
||||||
"predictiveBackGestureEnabled": false
|
"predictiveBackGestureEnabled": false,
|
||||||
|
"permissions": ["android.permission.CAMERA"],
|
||||||
|
"package": "com.anonymous.ai_questions_app"
|
||||||
},
|
},
|
||||||
"web": {
|
"web": {
|
||||||
"output": "static",
|
"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": {
|
"experiments": {
|
||||||
"typedRoutes": true,
|
"typedRoutes": true,
|
||||||
|
|||||||
@ -49,7 +49,7 @@ export default function TestsScreen() {
|
|||||||
selectedValue={category ? `${category}` : undefined}
|
selectedValue={category ? `${category}` : undefined}
|
||||||
onValueChange={handleChangeCategory}
|
onValueChange={handleChangeCategory}
|
||||||
placeholder="Select category" />
|
placeholder="Select category" />
|
||||||
<Button>
|
<Button onPress={() => router.push('/qr')}>
|
||||||
<ButtonText><FontAwesome5 name="qrcode" size={18} /></ButtonText>
|
<ButtonText><FontAwesome5 name="qrcode" size={18} /></ButtonText>
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
</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({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
alignItems: "flex-start",
|
width: "100%"
|
||||||
},
|
},
|
||||||
top: {
|
top: {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
|
|||||||
@ -106,7 +106,7 @@ const Answer = ({
|
|||||||
{isTextType ? (
|
{isTextType ? (
|
||||||
<FontAwesome5 name="quote-left" />
|
<FontAwesome5 name="quote-left" />
|
||||||
) : (
|
) : (
|
||||||
<ThemedText darkColor="#fff" lightColor="#fff">
|
<ThemedText darkColor="#000" lightColor="#fff">
|
||||||
{answer.id}
|
{answer.id}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -33,12 +33,13 @@ const CustomSelect = ({
|
|||||||
return options;
|
return options;
|
||||||
}, [options, noneOption]);
|
}, [options, noneOption]);
|
||||||
const backgroundColor = useThemeColor({ }, "background");
|
const backgroundColor = useThemeColor({ }, "background");
|
||||||
|
const metaColor = useThemeColor({}, "meta");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select className={className} onValueChange={onValueChange} selectedValue={selectedValue} defaultValue={defaultValue}>
|
<Select className={className} onValueChange={onValueChange} selectedValue={selectedValue} defaultValue={defaultValue}>
|
||||||
<SelectTrigger className="justify-between" variant="outline" size="md" style={{ backgroundColor }}>
|
<SelectTrigger className="justify-between" variant="outline" size="md" style={{ backgroundColor }}>
|
||||||
<SelectInput placeholder={placeholder} />
|
<SelectInput placeholder={placeholder} />
|
||||||
<FontAwesome5 className="mr-3" name="chevron-down" />
|
<FontAwesome5 style={{color: metaColor}} className="mr-3" name="chevron-down" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectPortal>
|
<SelectPortal>
|
||||||
<SelectBackdrop />
|
<SelectBackdrop />
|
||||||
|
|||||||
25
package-lock.json
generated
25
package-lock.json
generated
@ -47,6 +47,7 @@
|
|||||||
"react-native-svg": "^15.15.1",
|
"react-native-svg": "^15.15.1",
|
||||||
"react-native-toast-notifications": "^3.4.0",
|
"react-native-toast-notifications": "^3.4.0",
|
||||||
"react-native-vector-icons": "^10.3.0",
|
"react-native-vector-icons": "^10.3.0",
|
||||||
|
"react-native-vision-camera": "^4.7.3",
|
||||||
"react-native-web": "~0.21.0",
|
"react-native-web": "~0.21.0",
|
||||||
"react-native-worklets": "^0.5.2",
|
"react-native-worklets": "^0.5.2",
|
||||||
"react-stately": "^3.43.0",
|
"react-stately": "^3.43.0",
|
||||||
@ -14687,6 +14688,30 @@
|
|||||||
"node": ">=10"
|
"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": {
|
"node_modules/react-native-web": {
|
||||||
"version": "0.21.2",
|
"version": "0.21.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz",
|
||||||
|
|||||||
@ -5,8 +5,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "expo start",
|
"start": "expo start",
|
||||||
"reset-project": "node ./scripts/reset-project.js",
|
"reset-project": "node ./scripts/reset-project.js",
|
||||||
"android": "expo start --android",
|
"android": "expo run:android",
|
||||||
"ios": "expo start --ios",
|
"ios": "expo run:ios",
|
||||||
"web": "expo start --web",
|
"web": "expo start --web",
|
||||||
"lint": "expo lint"
|
"lint": "expo lint"
|
||||||
},
|
},
|
||||||
@ -50,6 +50,7 @@
|
|||||||
"react-native-svg": "^15.15.1",
|
"react-native-svg": "^15.15.1",
|
||||||
"react-native-toast-notifications": "^3.4.0",
|
"react-native-toast-notifications": "^3.4.0",
|
||||||
"react-native-vector-icons": "^10.3.0",
|
"react-native-vector-icons": "^10.3.0",
|
||||||
|
"react-native-vision-camera": "^4.7.3",
|
||||||
"react-native-web": "~0.21.0",
|
"react-native-web": "~0.21.0",
|
||||||
"react-native-worklets": "^0.5.2",
|
"react-native-worklets": "^0.5.2",
|
||||||
"react-stately": "^3.43.0",
|
"react-stately": "^3.43.0",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user