From c77be06eca6b1610b26600b622bd743797d9648f Mon Sep 17 00:00:00 2001 From: it21227004 Date: Sat, 10 May 2025 06:13:04 +0530 Subject: [PATCH 1/6] testing --- CeylonCare/app.json | 15 +- .../app/pages/AR_component/ARAvatarScreen.tsx | 873 ++++++------------ CeylonCare/package-lock.json | 68 +- 3 files changed, 327 insertions(+), 629 deletions(-) diff --git a/CeylonCare/app.json b/CeylonCare/app.json index 0a487125..47573643 100644 --- a/CeylonCare/app.json +++ b/CeylonCare/app.json @@ -12,6 +12,7 @@ "ios": { "supportsTablet": true, "infoPlist": { + "NSCameraUsageDescription": "This app uses the camera for real-time pose detection to guide your yoga practice.", "NSMicrophoneUsageDescription": "We need microphone access to record your voice for the chatbot." } }, @@ -20,7 +21,11 @@ "foregroundImage": "", "backgroundColor": "#ffffff" }, - "permissions": ["android.permission.RECORD_AUDIO"] + "permissions": [ + "android.permission.CAMERA", + "android.permission.RECORD_AUDIO", + "android.permission.WEBVIEW_MEDIA" + ] }, "web": { "bundler": "metro", @@ -39,13 +44,7 @@ } ], "expo-asset", - "expo-font", - [ - "expo-camera", - { - "cameraPermission": "Allow this app to use the camera for AR features." - } - ] + "expo-font" ], "experiments": { "typedRoutes": true diff --git a/CeylonCare/app/pages/AR_component/ARAvatarScreen.tsx b/CeylonCare/app/pages/AR_component/ARAvatarScreen.tsx index 80e87ff0..b1e58c1d 100644 --- a/CeylonCare/app/pages/AR_component/ARAvatarScreen.tsx +++ b/CeylonCare/app/pages/AR_component/ARAvatarScreen.tsx @@ -1,15 +1,14 @@ -import React, { useState, useEffect, useRef } from 'react'; +import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react'; import { View, Text, StyleSheet, - Platform, TouchableOpacity, ActivityIndicator, ScrollView, + PermissionsAndroid, + Platform, } from 'react-native'; -import * as Camera from 'expo-camera'; -import { useCameraPermissions } from 'expo-camera'; import WebView from 'react-native-webview'; import { LinearGradient } from 'expo-linear-gradient'; import Ionicons from 'react-native-vector-icons/Ionicons'; @@ -21,6 +20,7 @@ type Recommendation = { name: string; ar_pose?: string; correct_pose_landmarks?: PoseLandmark[]; + reference_video?: string; }; // Define Pose Landmark Type @@ -32,14 +32,14 @@ type PoseLandmark = { }; const ARAvatarScreen = ({ route, navigation }) => { - const { recommendations = [{ name: route.params?.therapyName, ar_pose: route.params?.arPoseUrl }] } = route.params || {}; - console.log('[DEBUG] Route params received:', JSON.stringify(route.params, null, 2)); + const params = useMemo(() => route.params || {}, [route.params]); + const recommendations = useMemo( + () => [{ name: params.therapyName, ar_pose: params.arPoseUrl, reference_video: params.referenceVideo }], + [params.therapyName, params.arPoseUrl, params.referenceVideo] + ); + console.log('[DEBUG] Route params:', JSON.stringify(params, null, 2)); - // State variables - const [permission, requestPermission] = useCameraPermissions(); - const [isCameraReady, setIsCameraReady] = useState(false); const [isWebViewValid, setIsWebViewValid] = useState(false); - const [cameraError, setCameraError] = useState(null); const [webViewError, setWebViewError] = useState(null); const [isModelLoaded, setIsModelLoaded] = useState(false); const [isAnimating, setIsAnimating] = useState(false); @@ -47,283 +47,227 @@ const ARAvatarScreen = ({ route, navigation }) => { const [currentPoseIndex, setCurrentPoseIndex] = useState(0); const [poseRecommendations, setPoseRecommendations] = useState(recommendations); const [landmarks, setLandmarks] = useState([]); - const [feedback, setFeedback] = useState('Please ensure your full body is visible in the camera frame.'); + const [feedback, setFeedback] = useState('Please stand 2-3 meters back to ensure your full body is visible.'); const [poseDetectionError, setPoseDetectionError] = useState(null); const [isPoseWebViewInitialized, setIsPoseWebViewInitialized] = useState(false); - const [useCameraView, setUseCameraView] = useState(true); - const [zoom, setZoom] = useState(0); // Zoom level state + const [isCalibrated, setIsCalibrated] = useState(false); + const [calibrationLandmarks, setCalibrationLandmarks] = useState([]); + const [language, setLanguage] = useState<'en' | 'si'>('en'); + const [hasCameraPermission, setHasCameraPermission] = useState(null); const webViewRef = useRef(null); const poseWebViewRef = useRef(null); - // Lock to landscape on mount, unlock on unmount useEffect(() => { - console.log('[DEBUG] ARAvatarScreen component mounted'); - const lockOrientation = async () => { + console.log('[DEBUG] Mounting ARAvatarScreen'); + return () => console.log('[DEBUG] Unmount reason: component cleanup'); + }, []); + + useEffect(() => { + const requestCameraPermission = async () => { try { - console.log('[DEBUG] Attempting to lock screen to landscape'); - const currentOrientation = await ScreenOrientation.getOrientationAsync(); - console.log('[DEBUG] Current orientation:', currentOrientation); - await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE); - console.log('[INFO] Screen successfully locked to landscape'); + if (Platform.OS === 'android') { + const granted = await PermissionsAndroid.request( + PermissionsAndroid.PERMISSIONS.CAMERA, + { + title: 'Camera Permission', + message: 'This app uses the camera for pose detection.', + buttonPositive: 'OK', + buttonNegative: 'Cancel', + } + ); + setHasCameraPermission(granted === PermissionsAndroid.RESULTS.GRANTED); + console.log('[INFO] Android camera permission:', granted); + } else { + setHasCameraPermission(true); + console.log('[INFO] iOS camera permission: assumed granted'); + } } catch (error) { - console.error('[ERROR] Failed to lock orientation:', error.message); + console.error('[ERROR] Permission request failed:', error.message); + setHasCameraPermission(false); } }; + requestCameraPermission(); + }, []); - const unlockOrientation = async () => { + useEffect(() => { + const lockOrientation = async () => { try { - console.log('[DEBUG] Attempting to unlock screen orientation'); - await ScreenOrientation.unlockAsync(); - console.log('[INFO] Screen orientation successfully unlocked'); + await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE); + console.log('[INFO] Locked to landscape'); } catch (error) { - console.error('[ERROR] Failed to unlock orientation:', error.message); + console.error('[ERROR] Lock orientation failed:', error.message); } }; - lockOrientation(); - return () => { - console.log('[DEBUG] ARAvatarScreen component unmounting'); - unlockOrientation(); - }; + return () => ScreenOrientation.unlockAsync().catch((error) => console.error('[ERROR] Unlock orientation failed:', error.message)); }, []); - // Validate components useEffect(() => { - console.log('[DEBUG] Validating essential components'); - if (!Camera.CameraView) { - console.error('[ERROR] CameraView component unavailable'); - setCameraError('Camera component unavailable'); - } else { - console.log('[INFO] CameraView component validated'); - } - if (!WebView) { - console.error('[ERROR] WebView component unavailable'); - setIsWebViewValid(false); - } else { - console.log('[INFO] WebView component validated'); - setIsWebViewValid(true); - } - if (!navigation?.navigate) { - console.error('[ERROR] Navigation prop is invalid'); - } else { - console.log('[INFO] Navigation prop validated'); - } + console.log('[DEBUG] Validating components'); + setIsWebViewValid(!!WebView); + if (!navigation?.navigate) console.error('[ERROR] Invalid navigation prop'); }, [navigation]); - // Fetch therapy details from backend API - useEffect(() => { - const fetchTherapyDetails = async () => { - console.log('[DEBUG] Fetching therapy details for recommendations'); - try { - const updatedRecommendations = await Promise.all( - recommendations.map(async (therapy: Recommendation) => { - console.log('[DEBUG] Fetching details for therapy:', therapy.name); - try { - const response = await axios.get(`http://192.168.60.107:5000/therapy_details/${encodeURIComponent(therapy.name)}`, { - timeout: 10000, - }); - console.log('[DEBUG] API response for therapy details:', JSON.stringify(response.data, null, 2)); - const data = response.data; - if (!data.ar_pose) { - console.warn('[WARN] No ar_pose provided for:', therapy.name); - } - if (!data.correct_pose_landmarks || !data.correct_pose_landmarks.length) { - console.warn('[WARN] No correct_pose_landmarks provided for:', therapy.name); - } - return { - ...therapy, - ar_pose: data.ar_pose || therapy.ar_pose, - correct_pose_landmarks: data.correct_pose_landmarks || [], - }; - } catch (error) { - console.error('[ERROR] Failed to fetch details for therapy:', therapy.name, error.message); - return therapy; - } - }) - ); - setPoseRecommendations(updatedRecommendations); - console.log('[INFO] Updated recommendations with therapy details:', JSON.stringify(updatedRecommendations, null, 2)); - } catch (error) { - console.error('[ERROR] Failed to fetch therapy details:', error.message); - } - }; - - if (recommendations.length > 0) { - console.log('[DEBUG] Recommendations length > 0, initiating fetch'); - fetchTherapyDetails(); - } else { - console.warn('[WARN] No recommendations provided'); + const fetchTherapyDetails = useCallback(async () => { + try { + const updatedRecommendations = await Promise.all( + recommendations.map(async (therapy) => { + try { + const response = await axios.get( + `http://192.168.8.134:5000/therapy_details/${encodeURIComponent(therapy.name)}`, + { timeout: 10000 } + ); + console.log('[DEBUG] Therapy details:', JSON.stringify(response.data, null, 2)); + return { + ...therapy, + ar_pose: response.data.ar_pose || therapy.ar_pose, + correct_pose_landmarks: response.data.correct_pose_landmarks || [], + reference_video: response.data.reference_video || therapy.referenceVideo, + }; + } catch (error) { + console.error('[ERROR] Fetch therapy failed:', therapy.name, error.message); + return therapy; + } + }) + ); + setPoseRecommendations(updatedRecommendations); + } catch (error) { + console.error('[ERROR] Fetch therapy details failed:', error.message); } }, [recommendations]); - // Handle camera permission useEffect(() => { - if (!permission) { - console.log('[DEBUG] Camera permission not yet initialized'); - return; - } - if (permission.status !== 'granted') { - console.log('[DEBUG] Camera permission not granted, requesting...'); - requestPermission(); - } else { - console.log('[INFO] Camera permission already granted'); - } - }, [permission, requestPermission]); + if (recommendations.length > 0) fetchTherapyDetails(); + }, [fetchTherapyDetails]); - // Monitor pose detection useEffect(() => { - console.log('[DEBUG] Monitoring pose detection, landmarks length:', landmarks.length); - const timeout = setTimeout(() => { - if (!landmarks.length && !poseDetectionError && isPoseWebViewInitialized) { - console.warn('[WARN] No pose landmarks detected after 10 seconds'); - setPoseDetectionError('Pose detection failed: No landmarks detected. Ensure your full body is visible or try disabling camera feed.'); - setUseCameraView(false); // Disable CameraView to test Pose WebView - } - }, 10000); - - return () => clearTimeout(timeout); - }, [landmarks, poseDetectionError, isPoseWebViewInitialized]); + if (!landmarks.length && !poseDetectionError && isPoseWebViewInitialized && !isCalibrated) { + const timeout = setTimeout(() => { + setPoseDetectionError( + 'No landmarks detected. Ensure good lighting, stand 2-3 meters away, wear fitted clothing.' + ); + }, 15000); + return () => clearTimeout(timeout); + } + }, [landmarks, poseDetectionError, isPoseWebViewInitialized, isCalibrated]); - // Toggle animation with WebView communication const toggleAnimation = () => { - if (!isModelLoaded) { - console.log('[DEBUG] Animation toggle ignored: model not loaded'); - return; - } + if (!isModelLoaded) return; setIsAnimating((prev) => { const newState = !prev; - console.log('[DEBUG] Toggling animation state to:', newState); if (isWebViewBridgeReady && webViewRef.current) { - const message = newState ? 'start' : 'stop'; - console.log('[DEBUG] Sending message to AR WebView:', message); - try { - webViewRef.current.postMessage(message); - console.log('[INFO] Message sent to AR WebView successfully'); - } catch (error) { - console.error('[ERROR] Failed to send message to AR WebView:', error.message); - } - } else { - console.warn('[WARN] AR WebView bridge not ready or ref missing'); + webViewRef.current.postMessage(newState ? 'start' : 'stop'); + console.log('[INFO] Animation toggled:', newState); } return newState; }); }; - // Switch to a different pose const switchPose = (index: number) => { - console.log('[DEBUG] Attempting to switch pose to index:', index); - if (index < 0 || index >= poseRecommendations.length) { - console.warn('[WARN] Invalid pose index:', index); - return; - } + if (index < 0 || index >= poseRecommendations.length) return; setCurrentPoseIndex(index); setIsModelLoaded(false); setLandmarks([]); - setFeedback('Please ensure your full body is visible in the camera frame.'); + setFeedback('Please stand 2-3 meters back to ensure your full body is visible.'); setPoseDetectionError(null); - if (webViewRef.current && isWebViewBridgeReady) { - console.log('[DEBUG] Stopping current animation before switching'); - webViewRef.current.postMessage('stop'); - } + setIsCalibrated(false); + setCalibrationLandmarks([]); + if (webViewRef.current && isWebViewBridgeReady) webViewRef.current.postMessage('stop'); console.log('[INFO] Switched to pose:', poseRecommendations[index].name); }; - // Compare user pose with correct pose and provide feedback + const calibratePose = () => { + if (landmarks.length) { + setCalibrationLandmarks(landmarks); + setIsCalibrated(true); + setFeedback(language === 'en' ? 'Calibration complete. Try the pose now.' : 'කැලිබ්‍රේෂන් සම්පූර්ණයි.'); + console.log('[INFO] Calibration set:', JSON.stringify(landmarks, null, 2)); + } else { + setFeedback(language === 'en' ? 'No landmarks detected for calibration.' : 'කැලිබ්‍රේෂන් සඳහා බිම් සලකුණු නැත.'); + } + }; + + const retryPoseDetection = () => { + setPoseDetectionError(null); + setLandmarks([]); + setIsPoseWebViewInitialized(false); + if (poseWebViewRef.current) poseWebViewRef.current.reload(); + console.log('[INFO] Retrying pose detection'); + }; + useEffect(() => { const comparePoses = () => { const currentPose = poseRecommendations[currentPoseIndex]; - console.log('[DEBUG] Comparing poses for:', currentPose?.name); - if (!currentPose) { - console.log('[DEBUG] Skipping comparison: currentPose is undefined'); - setFeedback('Error: No pose selected'); + if (!currentPose || !currentPose.correct_pose_landmarks?.length) { + setFeedback(language === 'en' ? 'Error: No reference pose data.' : 'දෝෂය: යොමු ඉරියව් දත්ත නැත.'); return; } if (!landmarks.length) { - console.log('[DEBUG] Skipping comparison: No detected landmarks'); - setFeedback('No pose detected. Please step back to ensure your full body is visible in the camera.'); - return; - } - if (!currentPose.correct_pose_landmarks || !currentPose.correct_pose_landmarks.length) { - console.log('[DEBUG] Skipping comparison: No correct pose landmarks'); - setFeedback('Error: No reference pose data available. Please contact support.'); + setFeedback(language === 'en' ? 'No pose detected.' : 'ඉරියව්ව හඳුනාගත නොහැක.'); return; } - console.log('[DEBUG] Detected landmarks:', JSON.stringify(landmarks, null, 2)); - console.log('[DEBUG] Correct pose landmarks:', JSON.stringify(currentPose.correct_pose_landmarks, null, 2)); - let feedbackMessage = ''; - currentPose.correct_pose_landmarks.forEach((correct: PoseLandmark) => { - const detected = landmarks.find((l: PoseLandmark) => l.name === correct.name); + const normalizedLandmarks = isCalibrated + ? landmarks.map((lm) => { + const calib = calibrationLandmarks.find((c) => c.name === lm.name); + return calib + ? { ...lm, x: lm.x - calib.x + 0.5, y: lm.y - calib.y + 0.5 } + : lm; + }) + : landmarks; + + currentPose.correct_pose_landmarks.forEach((correct) => { + const detected = normalizedLandmarks.find((l) => l.name === correct.name); if (detected) { const xDiff = Math.abs(detected.x - correct.x); const yDiff = Math.abs(detected.y - correct.y); - console.log(`[DEBUG] Comparing ${correct.name}: xDiff=${xDiff}, yDiff=${yDiff}`); - if (xDiff > 0.1 || yDiff > 0.1) { - feedbackMessage += `Adjust ${correct.name} position\n`; + if (xDiff > 0.15 || yDiff > 0.15) { + feedbackMessage += language === 'en' + ? `Adjust ${correct.name} position\n` + : `${correct.name} ස්ථානය සකස් කරන්න\n`; } } else { - console.warn(`[WARN] Landmark ${correct.name} not detected in landmarks`); - feedbackMessage += `Cannot detect ${correct.name}\n`; + feedbackMessage += language === 'en' + ? `Cannot detect ${correct.name}\n` + : `${correct.name} හඳුනාගත නොහැක\n`; } }); - const finalFeedback = feedbackMessage || 'Pose looks good!'; - setFeedback(finalFeedback); - console.log('[INFO] Feedback set to:', finalFeedback); + setFeedback(feedbackMessage || (language === 'en' ? 'Pose looks good!' : 'ඉරියව්ව හොඳයි!')); + console.log('[INFO] Feedback:', feedbackMessage || 'Pose looks good!'); }; - comparePoses(); - }, [landmarks, currentPoseIndex, poseRecommendations]); + }, [landmarks, currentPoseIndex, poseRecommendations, isCalibrated, language]); - // End session and navigate back const handleEndSession = async () => { - console.log('[DEBUG] Initiating end session'); - try { - if (webViewRef.current && isWebViewBridgeReady) { - console.log('[DEBUG] Sending stop message to AR WebView'); - webViewRef.current.postMessage('stop'); - } - console.log('[DEBUG] Locking orientation to portrait'); - await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP); - console.log('[INFO] Orientation locked to portrait, navigating back'); - navigation.goBack(); - } catch (error) { - console.error('[ERROR] Failed to end session:', error.message); - } - }; - - // Zoom In - const zoomIn = () => { - setZoom(prevZoom => Math.min(prevZoom + 0.1, 1)); - console.log('[DEBUG] Zooming in, new zoom level:', Math.min(zoom + 0.1, 1)); + if (webViewRef.current && isWebViewBridgeReady) webViewRef.current.postMessage('stop'); + await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP); + navigation.goBack(); }; - // Zoom Out - const zoomOut = () => { - setZoom(prevZoom => Math.max(prevZoom - 0.1, 0)); - console.log('[DEBUG] Zooming out, new zoom level:', Math.max(zoom - 0.1, 0)); - }; + const toggleLanguage = () => setLanguage(language === 'en' ? 'si' : 'en'); - // Permission loading state - if (!permission) { - console.log('[DEBUG] Waiting for camera permission initialization'); + if (hasCameraPermission === null) { return ( - Checking camera permission... + {language === 'en' ? 'Checking camera permission...' : 'කැමරා අවසරය පරීක්ෂා කරමින්...'} ); } - // Permission denied state - if (permission.status !== 'granted') { - console.log('[DEBUG] Camera permission denied'); + if (hasCameraPermission === false) { return ( - Camera permission required - - Retry + {language === 'en' ? 'Camera permission required.' : 'කැමරා අවසරය අවශ්‍යයි.'} + { + if (Platform.OS === 'android') { + const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA); + setHasCameraPermission(granted === PermissionsAndroid.RESULTS.GRANTED); + } + }}> + {language === 'en' ? 'Retry' : 'නැවත උත්සාහ කරන්න'} ); @@ -331,40 +275,24 @@ const ARAvatarScreen = ({ route, navigation }) => { const currentPose = poseRecommendations[currentPoseIndex]; const arPoseUrl = currentPose?.ar_pose; - console.log('[DEBUG] Current AR pose URL:', arPoseUrl); - // AR WebView HTML const getARWebViewHtml = () => { - if (!arPoseUrl) { - console.warn('[WARN] No AR pose URL available'); - return '

No AR pose URL available

'; - } - console.log('[DEBUG] Generating AR WebView HTML with URL:', arPoseUrl); + if (!arPoseUrl) return '

No AR pose URL available

'; return ` - + - - - - + + @@ -396,13 +319,11 @@ const ARAvatarScreen = ({ route, navigation }) => { `; }; - // Pose Estimation WebView HTML with Canvas Overlay const getPoseEstimationHtml = () => { - console.log('[DEBUG] Generating Pose Estimation WebView HTML'); return ` - + - - - - - - - - - - - `; - }; - - const getPoseEstimationHtml = () => { - return ` - - - - - - - - - - - - `; - }; - return ( - {isWebViewValid && arPoseUrl && !webViewError ? ( - { - setWebViewError(e.nativeEvent.description); - console.error('[ERROR] AR WebView error:', e.nativeEvent.description); - }} - onMessage={(event) => { - const data = event.nativeEvent.data; - console.log('[DEBUG] AR WebView message:', data); - if (data === 'bridge-ready') setIsWebViewBridgeReady(true); - else if (data === 'model-loaded') setIsModelLoaded(true); - else if (data.startsWith('model-error:')) setWebViewError('Failed to load AR model'); - }} - /> - ) : ( - - {webViewError || (language === 'en' ? 'AR WebView error' : 'AR WebView දෝෂය')} - - )} - - {isWebViewValid && hasCameraPermission && ( - { - const data = event.nativeEvent.data; - console.log('[DEBUG] Pose WebView message:', data); - try { - if (data === 'Pose library initialized') setIsPoseWebViewInitialized(true); - else if (data.startsWith('Error:')) setPoseDetectionError(data); - else if (data === 'No landmarks detected') setLandmarks([]); - else { - const parsedLandmarks = JSON.parse(data); - setLandmarks(parsedLandmarks); - setPoseDetectionError(null); - } - } catch (error) { - setPoseDetectionError('Failed to parse pose data'); - console.error('[ERROR] Parse error:', error.message); - } - }} - onError={(e) => { - setPoseDetectionError('Pose WebView failed to load: ' + e.nativeEvent.description); - console.error('[ERROR] Pose WebView error:', e.nativeEvent.description); - }} - /> - )} - - {(feedback || poseDetectionError) && ( - - {poseDetectionError || feedback} - {poseDetectionError && ( - - {language === 'en' ? 'Retry Detection' : 'නැවත හඳුනාගැනීම'} - - )} - - )} - - - navigation.goBack()}> - - - {language === 'en' ? 'AR Yoga Trainer' : 'AR යෝග ගුරු'} - - - - {poseRecommendations.map((therapy, index) => ( - switchPose(index)} - > - {therapy.name} - - ))} - - - - {language === 'en' ? 'Calibrate' : 'කැලිබ්‍රේට්'} - - - - {language === 'en' ? 'සිංහල' : 'English'} + setIsCameraReady(true)} /> + + + + + + {feedback} + navigation.goBack()} style={styles.backButton}> + Back - - {!isModelLoaded && ( - - - {language === 'en' ? 'Loading AR Avatar...' : 'AR අවතාරය පූරණය වෙමින්...'} - - )} - - - - {language === 'en' ? (isAnimating ? 'Pause' : 'Start') : (isAnimating ? 'විරාමය' : 'ආරම්භ')} - - - - - {language === 'en' ? 'End' : 'අවසන්'} + setIsAnimating((prev) => !prev)} style={[styles.startButton, isAnimating ? styles.startButtonActive : null]}> + {isAnimating ? 'Stop Animation' : 'Start Animation'} ); }; const styles = StyleSheet.create({ - container: { flex: 1, backgroundColor: '#000' }, - header: { height: 60, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', paddingTop: 10 }, - backButton: { position: 'absolute', left: 15, top: 20 }, - headerText: { fontSize: 20, color: 'white', fontWeight: '600' }, - errorContainer: { flex: 1, justifyContent: 'center', alignItems: 'center' }, - errorText: { color: 'red', textAlign: 'center', fontSize: 16 }, - loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#fff' }, - loadingOverlay: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(0, 0, 0, 0.5)' }, - loadingText: { color: 'white', marginTop: 10, fontSize: 16 }, - fabPlay: { position: 'absolute', bottom: 20, right: 20, flexDirection: 'row', alignItems: 'center', backgroundColor: '#00BBD3', padding: 15, borderRadius: 30, elevation: 5 }, - fabEnd: { position: 'absolute', bottom: 20, left: 20, flexDirection: 'row', alignItems: 'center', backgroundColor: '#FF4D4F', padding: 15, borderRadius: 30, elevation: 5 }, - fabText: { color: 'white', marginLeft: 10, fontSize: 16 }, - fabDisabled: { opacity: 0.5 }, - retryButton: { marginTop: 20, backgroundColor: '#00BBD3', paddingVertical: 10, paddingHorizontal: 20, borderRadius: 25 }, - retryButtonText: { color: 'white', fontSize: 16 }, - poseSwitchContainer: { position: 'absolute', bottom: 100, flexDirection: 'row', backgroundColor: 'rgba(0, 0, 0, 0.5)', padding: 5 }, - poseButton: { padding: 10, margin: 5, backgroundColor: '#00BBD3', borderRadius: 5 }, - activePoseButton: { backgroundColor: '#33E4DB' }, - poseButtonText: { color: 'white', fontSize: 14 }, - feedbackContainer: { position: 'absolute', top: 100, backgroundColor: 'rgba(0, 0, 0, 0.7)', padding: 15, borderRadius: 5, alignSelf: 'center', maxWidth: '80%' }, - feedbackText: { color: 'white', fontSize: 16, textAlign: 'center' }, - calibrateButton: { position: 'absolute', top: 70, right: 20, backgroundColor: '#00BBD3', padding: 10, borderRadius: 5 }, - calibrateButtonDisabled: { opacity: 0.5 }, - calibrateButtonText: { color: 'white', fontSize: 14 }, - languageButton: { position: 'absolute', top: 70, left: 20, backgroundColor: '#00BBD3', padding: 10, borderRadius: 5 }, - languageButtonText: { color: 'white', fontSize: 14 }, + container: { flex: 1, backgroundColor: '#000', justifyContent: 'flex-end' }, + camera: { position: 'absolute', top: 0, left: 0, width: '100%', height: '70%', zIndex: 0 }, + canvas: { position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', zIndex: 1 }, + feedback: { position: 'absolute', bottom: 150, width: '100%', textAlign: 'center', color: 'white', fontSize: 18, backgroundColor: 'rgba(0,0,0,0.5)', padding: 5, zIndex: 2 }, + message: { textAlign: 'center', paddingBottom: 10, color: 'white', fontSize: 16 }, + button: { padding: 10, backgroundColor: '#00BBD3', borderRadius: 5, alignSelf: 'center', zIndex: 2 }, + buttonText: { color: 'white', fontSize: 16 }, + backButton: { position: 'absolute', bottom: 10, left: 10, padding: 15, backgroundColor: '#00BBD3', borderRadius: 25, zIndex: 2 }, + startButton: { position: 'absolute', bottom: 70, alignSelf: 'center', padding: 15, backgroundColor: '#00BBD3', borderRadius: 25, zIndex: 2 }, + startButtonActive: { backgroundColor: '#FF4444' }, }); export default ARAvatarScreen; \ No newline at end of file diff --git a/CeylonCare/app/pages/AR_component/CameraTest.tsx b/CeylonCare/app/pages/AR_component/CameraTest.tsx new file mode 100644 index 00000000..9a4528e9 --- /dev/null +++ b/CeylonCare/app/pages/AR_component/CameraTest.tsx @@ -0,0 +1,69 @@ +import { CameraView, CameraType, useCameraPermissions } from 'expo-camera'; +import { useState } from 'react'; +import { Button, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; + +export default function App() { + const [facing, setFacing] = useState('back'); + const [permission, requestPermission] = useCameraPermissions(); + + if (!permission) { + // Camera permissions are still loading. + return ; + } + + if (!permission.granted) { + // Camera permissions are not granted yet. + return ( + + We need your permission to show the camera +