diff --git a/App.js b/App.js index 204cfc738e5969c879a3a1b169c1e1ef1726639c..9646c48b40542dec9981b06a528ab8d83252bf84 100644 --- a/App.js +++ b/App.js @@ -1,87 +1,8 @@ -import React, { useEffect, useRef, useState } from 'react'; -import { View, ActivityIndicator, StyleSheet, Pressable, Text } from 'react-native'; -import { Camera, useCameraDevice, useCameraPermission } from 'react-native-vision-camera'; +import React from 'react'; +import AppNavigator from './navigation/AppNavigation'; +import 'react-native-gesture-handler'; -export default function App() { - const device = useCameraDevice('back'); - const { hasPermission, requestPermission } = useCameraPermission(); - const camera = useRef(null); - - const [isRecording, setIsRecording] = useState(false); - const [photo, setPhoto] = useState(null); - const [video, setVideo] = useState(null); - - useEffect(() => { - if (!hasPermission) requestPermission(); - }, [hasPermission]); - - if (!hasPermission) return <ActivityIndicator />; - if (!device) return <Text>Camera device not found</Text>; - - const onTakePicture = async () => { - if (!camera.current) return; - const photo = await camera.current.takePhoto(); - setPhoto(photo); - console.log("Photo captured:", photo.path); - }; - const onStartRecording = async () => { - if (!camera.current) return; - setIsRecording(true); - camera.current.startRecording({ - onRecordingFinished: (video) => { - setIsRecording(false); - setVideo(video); - console.log("Video saved at:", video.path); - }, - onRecordingError: (error) => { - console.error(error); - setIsRecording(false); - }, - }); - }; - - const onStopRecording = () => { - camera.current?.stopRecording(); - }; - - return ( - <View style={styles.container}> - <Camera ref={camera} style={StyleSheet.absoluteFill} device={device} isActive={true} photo video audio /> - - {/* Capture Buttons */} - <View style={styles.controls}> - <Pressable onPress={onTakePicture} style={styles.captureButton}> - <Text style={styles.buttonText}>📷 Capture</Text> - </Pressable> - <Pressable onPress={isRecording ? onStopRecording : onStartRecording} style={[styles.captureButton, { backgroundColor: isRecording ? 'red' : 'white' }]}> - <Text style={styles.buttonText}>{isRecording ? '⹠Stop' : '🎥 Record'}</Text> - </Pressable> - </View> - </View> - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - backgroundColor: '#000', - }, - controls: { - position: 'absolute', - bottom: 50, - flexDirection: 'row', - width: '100%', - justifyContent: 'space-evenly', - }, - captureButton: { - padding: 10, - borderRadius: 10, - backgroundColor: 'white', - }, - buttonText: { - fontSize: 16, - fontWeight: 'bold', - }, -}); +export default function App() { + return <AppNavigator />; +} \ No newline at end of file diff --git a/navigation/AppNavigation.js b/navigation/AppNavigation.js new file mode 100644 index 0000000000000000000000000000000000000000..73a5359c791a7de49d838a1e07c885226aed212a --- /dev/null +++ b/navigation/AppNavigation.js @@ -0,0 +1,24 @@ +import React from 'react'; +import { NavigationContainer } from '@react-navigation/native'; +import { createStackNavigator } from '@react-navigation/stack'; +import CameraScreen from '../screens/CameraScreen'; +// import SwipeScreen from '../screens/SwipeScreen'; +// import MapScreen from '../screens/MapScreen'; +// import ProfileScreen from '../screens/ProfileScreen'; + +const Stack = createStackNavigator(); + +const AppNavigator = () => { + return ( + <NavigationContainer> + <Stack.Navigator initialRouteName="Camera"> + <Stack.Screen name="Camera" component={CameraScreen} /> + {/* <Stack.Screen name="Swipe" component={SwipeScreen} /> + <Stack.Screen name="Map" component={MapScreen} /> + <Stack.Screen name="Profile" component={ProfileScreen} /> */} + </Stack.Navigator> + </NavigationContainer> + ); +}; + +export default AppNavigator; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6a47458c547d579625917279d59c8ffadb4d5985..c5a3cb039ac179457caed84b3f09230845c3621f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,11 +8,16 @@ "name": "expophotography", "version": "1.0.0", "dependencies": { + "@react-navigation/native": "^7.0.15", + "@react-navigation/stack": "^7.1.2", "expo": "~52.0.36", "expo-dev-client": "~5.0.12", "expo-status-bar": "~2.0.1", "react": "18.3.1", "react-native": "0.76.7", + "react-native-gesture-handler": "^2.24.0", + "react-native-safe-area-context": "^5.3.0", + "react-native-screens": "^4.9.1", "react-native-vision-camera": "^4.6.4" }, "devDependencies": { @@ -2166,6 +2171,18 @@ "node": ">=6.9.0" } }, + "node_modules/@egjs/hammerjs": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz", + "integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==", + "license": "MIT", + "dependencies": { + "@types/hammerjs": "^2.0.36" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/@expo/bunyan": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@expo/bunyan/-/bunyan-4.0.1.tgz", @@ -4897,6 +4914,89 @@ } } }, + "node_modules/@react-navigation/core": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.4.0.tgz", + "integrity": "sha512-URiDluFl7cLA7GtOAsEvRqPmEMlSSXadqQ3wi9+Dl43dNRMqnoF76WQ9BCXeUPLydJq4yVte9XeMPyD6a0lY1g==", + "license": "MIT", + "dependencies": { + "@react-navigation/routers": "^7.2.0", + "escape-string-regexp": "^4.0.0", + "nanoid": "3.3.8", + "query-string": "^7.1.3", + "react-is": "^18.2.0", + "use-latest-callback": "^0.2.1", + "use-sync-external-store": "^1.2.2" + }, + "peerDependencies": { + "react": ">= 18.2.0" + } + }, + "node_modules/@react-navigation/elements": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.2.6.tgz", + "integrity": "sha512-UPeaCcEDSDRaxjG+qEHbur6jmNW/f9QNCyPsUt6NMgPEdbB5Z8K8oSx2swIaiCnvUbs/K5G3MuWkqQxGj8QXXA==", + "license": "MIT", + "dependencies": { + "color": "^4.2.3" + }, + "peerDependencies": { + "@react-native-masked-view/masked-view": ">= 0.2.0", + "@react-navigation/native": "^7.0.15", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0" + }, + "peerDependenciesMeta": { + "@react-native-masked-view/masked-view": { + "optional": true + } + } + }, + "node_modules/@react-navigation/native": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.0.15.tgz", + "integrity": "sha512-72PabJJ8VY3GM8i/DCutFW+ATED96ZV6NH+bW+ry1EL0ZFGHoie96H+KzTqktsrUbBw1rd9KXbEQhBQgo0N7iQ==", + "license": "MIT", + "dependencies": { + "@react-navigation/core": "^7.4.0", + "escape-string-regexp": "^4.0.0", + "fast-deep-equal": "^3.1.3", + "nanoid": "3.3.8", + "use-latest-callback": "^0.2.1" + }, + "peerDependencies": { + "react": ">= 18.2.0", + "react-native": "*" + } + }, + "node_modules/@react-navigation/routers": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.2.0.tgz", + "integrity": "sha512-lMyib39H4a//u+eiyt162U6TwCfI8zJbjl9ovjKtDddQ4/Vf7b8/OhyimnJH09N2CBfm4pv0gCV6Q0WnZcfaJg==", + "license": "MIT", + "dependencies": { + "nanoid": "3.3.8" + } + }, + "node_modules/@react-navigation/stack": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-7.1.2.tgz", + "integrity": "sha512-uRFec2SeZP7Urgekzake5AbWt1llsfxZdRqd9plOKnUTpSDhRO45d1XidgnB4eguJF4Yvdb8c2Ge3ZB3rvfCxg==", + "license": "MIT", + "dependencies": { + "@react-navigation/elements": "^2.2.6", + "color": "^4.2.3" + }, + "peerDependencies": { + "@react-navigation/native": "^7.0.15", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-gesture-handler": ">= 2.0.0", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, "node_modules/@segment/loosely-validate-event": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz", @@ -5004,6 +5104,12 @@ "@types/node": "*" } }, + "node_modules/@types/hammerjs": { + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz", + "integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==", + "license": "MIT" + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -6093,6 +6199,19 @@ "node": ">=6" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -6111,6 +6230,16 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/colorette": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", @@ -6359,6 +6488,15 @@ "node": ">=0.10.0" } }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -7235,6 +7373,15 @@ "node": ">=8" } }, + "node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -7683,6 +7830,21 @@ "hermes-estree": "0.23.1" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/hosted-git-info": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", @@ -10593,6 +10755,24 @@ "qrcode-terminal": "bin/qrcode-terminal.js" } }, + "node_modules/query-string": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", + "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", + "license": "MIT", + "dependencies": { + "decode-uri-component": "^0.2.2", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/queue": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", @@ -10689,6 +10869,18 @@ } } }, + "node_modules/react-freeze": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz", + "integrity": "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=17.0.0" + } + }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -10756,6 +10948,45 @@ } } }, + "node_modules/react-native-gesture-handler": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.24.0.tgz", + "integrity": "sha512-ZdWyOd1C8axKJHIfYxjJKCcxjWEpUtUWgTOVY2wynbiveSQDm8X/PDyAKXSer/GOtIpjudUbACOndZXCN3vHsw==", + "license": "MIT", + "dependencies": { + "@egjs/hammerjs": "^2.0.17", + "hoist-non-react-statics": "^3.3.0", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-safe-area-context": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.3.0.tgz", + "integrity": "sha512-glV9bwuozTjf/JDBIBm+ITnukHNaUT3nucgdeADwjtHsfEN3RL5UO6nq99vvdWv5j/O9yCZBvFncM1BBQ+UvpQ==", + "license": "MIT", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-screens": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.9.1.tgz", + "integrity": "sha512-3pIOu1YXTDClQfkgk2t7rIr7unrV6bviaXRJsOq1APNHLeCPrJ6m5Gy3pW5Ty+XBm9jRAbMqhpjiXZIjesOR6A==", + "license": "MIT", + "dependencies": { + "react-freeze": "^1.0.0", + "warn-once": "^0.1.0" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-vision-camera": { "version": "4.6.4", "resolved": "https://registry.npmjs.org/react-native-vision-camera/-/react-native-vision-camera-4.6.4.tgz", @@ -11511,6 +11742,21 @@ "node": ">= 5.10.0" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -11639,6 +11885,15 @@ "node": "*" } }, + "node_modules/split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -11723,6 +11978,15 @@ "node": ">= 0.10.0" } }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -12470,6 +12734,24 @@ "punycode": "^2.1.0" } }, + "node_modules/use-latest-callback": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.3.tgz", + "integrity": "sha512-7vI3fBuyRcP91pazVboc4qu+6ZqM8izPWX9k7cRnT8hbD5svslcknsh3S9BUhaK11OmgTV4oWZZVSeQAiV53SQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", + "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -12528,6 +12810,12 @@ "makeerror": "1.0.12" } }, + "node_modules/warn-once": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.1.tgz", + "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==", + "license": "MIT" + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", diff --git a/package.json b/package.json index 5a49c70b12909671513e57b6859d14bd12cc3431..e3ae1591b6f624dce5b64cbb30c8e35e872f54d0 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,16 @@ "web": "expo start --web" }, "dependencies": { + "@react-navigation/native": "^7.0.15", + "@react-navigation/stack": "^7.1.2", "expo": "~52.0.36", "expo-dev-client": "~5.0.12", "expo-status-bar": "~2.0.1", "react": "18.3.1", "react-native": "0.76.7", + "react-native-gesture-handler": "^2.24.0", + "react-native-safe-area-context": "^5.3.0", + "react-native-screens": "^4.9.1", "react-native-vision-camera": "^4.6.4" }, "devDependencies": { diff --git a/screens/CameraScreen.js b/screens/CameraScreen.js new file mode 100644 index 0000000000000000000000000000000000000000..fee348f845dc5c0253f3d656c02d631be75f2150 --- /dev/null +++ b/screens/CameraScreen.js @@ -0,0 +1,88 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { View, ActivityIndicator, StyleSheet, Pressable, Text } from 'react-native'; +import { Camera, useCameraDevice, useCameraPermission } from 'react-native-vision-camera'; + +const CameraScreen = () => { + const device = useCameraDevice('back'); + const { hasPermission, requestPermission } = useCameraPermission(); + const camera = useRef(null); + + const [isRecording, setIsRecording] = useState(false); + const [photo, setPhoto] = useState(null); + const [video, setVideo] = useState(null); + + useEffect(() => { + if (!hasPermission) requestPermission(); + }, [hasPermission]); + + if (!hasPermission) return <ActivityIndicator />; + if (!device) return <Text>Camera device not found</Text>; + + const onTakePicture = async () => { + if (!camera.current) return; + const photo = await camera.current.takePhoto(); + setPhoto(photo); + console.log("Photo captured:", photo.path); + }; + + const onStartRecording = async () => { + if (!camera.current) return; + setIsRecording(true); + camera.current.startRecording({ + onRecordingFinished: (video) => { + setIsRecording(false); + setVideo(video); + console.log("Video saved at:", video.path); + }, + onRecordingError: (error) => { + console.error(error); + setIsRecording(false); + }, + }); + }; + + const onStopRecording = () => { + camera.current?.stopRecording(); + }; + + return ( + <View style={styles.container}> + <Camera ref={camera} style={StyleSheet.absoluteFill} device={device} isActive={true} photo video audio /> + + <View style={styles.controls}> + <Pressable onPress={onTakePicture} style={styles.captureButton}> + <Text style={styles.buttonText}>📷 Capture</Text> + </Pressable> + <Pressable onPress={isRecording ? onStopRecording : onStartRecording} style={[styles.captureButton, { backgroundColor: isRecording ? 'red' : 'white' }]}> + <Text style={styles.buttonText}>{isRecording ? '⹠Stop' : '🎥 Record'}</Text> + </Pressable> + </View> + </View> + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + backgroundColor: '#000', + }, + controls: { + position: 'absolute', + bottom: 50, + flexDirection: 'row', + width: '100%', + justifyContent: 'space-evenly', + }, + captureButton: { + padding: 10, + borderRadius: 10, + backgroundColor: 'white', + }, + buttonText: { + fontSize: 16, + fontWeight: 'bold', + }, +}); + +export default CameraScreen; \ No newline at end of file diff --git a/screens/MapScreen.js b/screens/MapScreen.js new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391