diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c4bd5fb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*.json] +end_of_line = lf +charset = utf-8 +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..082d2b9 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +/react-native-vision-camera/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..51c47ad --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "react-native-vision-camera"] + path = react-native-vision-camera + url = https://dev.railbird.ai/railbird/react-native-vision-camera.git diff --git a/android/app/build.gradle b/android/app/build.gradle index 489dcc7..dcc7a44 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -174,9 +174,11 @@ dependencies { } else { implementation jscFlavor } + + implementation project(':react-native-vision-camera') } apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute(null, rootDir).text.trim(), "../native_modules.gradle"); applyNativeModulesAppBuildGradle(project) -apply plugin: 'com.google.gms.google-services' \ No newline at end of file +apply plugin: 'com.google.gms.google-services' diff --git a/android/app/src/main/java/android/railbird/app/MainApplication.java b/android/app/src/main/java/android/railbird/app/MainApplication.java index 38f84b5..7388170 100644 --- a/android/app/src/main/java/android/railbird/app/MainApplication.java +++ b/android/app/src/main/java/android/railbird/app/MainApplication.java @@ -15,6 +15,7 @@ import com.facebook.soloader.SoLoader; import expo.modules.ApplicationLifecycleDispatcher; import expo.modules.ReactNativeHostWrapper; +import com.mrousavy.camera.CameraPackage; import java.util.List; @@ -32,7 +33,8 @@ public class MainApplication extends Application implements ReactApplication { @SuppressWarnings("UnnecessaryLocalVariable") List packages = new PackageList(this).getPackages(); // Packages that cannot be autolinked yet can be added manually here, for example: - // packages.add(new MyReactNativePackage()); + // packages.add(new MyReactNativePackage()); + packages.add(new CameraPackage()); return packages; } diff --git a/android/build.gradle b/android/build.gradle index 63179df..b6f57d7 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -20,6 +20,7 @@ buildscript { classpath 'com.google.gms:google-services:4.3.3' classpath('com.android.tools.build:gradle:7.4.2') classpath('com.facebook.react:react-native-gradle-plugin') + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.22") } } diff --git a/android/settings.gradle b/android/settings.gradle index 2998473..eb532f8 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,10 +1,17 @@ rootProject.name = 'Railbird' apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle"); + +apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); + useExpoModules() apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute(null, rootDir).text.trim(), "../native_modules.gradle"); + applyNativeModulesSettingsGradle(settings) +include ':react-native-vision-camera' +project(':react-native-vision-camera').projectDir = new File(rootProject.projectDir, '../react-native-vision-camera/package/android') + include ':app' includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile()) diff --git a/app.json b/app.json index e9a87f7..7766581 100644 --- a/app.json +++ b/app.json @@ -11,9 +11,7 @@ "resizeMode": "contain", "backgroundColor": "#ffffff" }, - "assetBundlePatterns": [ - "**/*" - ], + "assetBundlePatterns": ["**/*"], "plugins": [ "@react-native-firebase/app", "@react-native-firebase/auth", diff --git a/babel.config.js b/babel.config.js index cf6bd4c..2f02724 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,16 +1,34 @@ -module.exports = function(api) { - api.cache(true); - return { - presets: ["babel-preset-expo"], - plugins: [ - ["module:react-native-dotenv", { - "moduleName": "@env", - "path": ".env", - "safe": false, - "allowUndefined": true, - "verbose": false, - }], - 'react-native-reanimated/plugin', - ], - }; +const path = require("path"); +const pak = require("./react-native-vision-camera/package/package.json"); + +module.exports = function (api) { + api.cache(true); + return { + presets: ["babel-preset-expo"], + plugins: [ + [ + "module:react-native-dotenv", + { + moduleName: "@env", + path: ".env", + safe: false, + allowUndefined: true, + verbose: false, + }, + ], + "react-native-reanimated/plugin", + [ + "module-resolver", + { + alias: { + [pak.name]: path.join( + __dirname, + "./react-native-vision-camera/package", + pak.source, + ), + }, + }, + ], + ], + }; }; diff --git a/component/video/camera.tsx b/component/video/camera.tsx index ef25fa8..df9983a 100644 --- a/component/video/camera.tsx +++ b/component/video/camera.tsx @@ -1,51 +1,71 @@ -import React, { useCallback, useRef, useState } from 'react' -import { StyleSheet, Text, View } from 'react-native' -import { Camera, useCameraPermission, useCameraDevice, useCameraFormat, PhotoFile, VideoFile, CameraRuntimeError } from 'react-native-vision-camera' -import { RecordingButton } from './capture-button' -import { useIsForeground } from './is-foreground' +import React, { useCallback, useRef, useState } from "react"; +import { Button, StyleSheet, Text, View } from "react-native"; +import { + Camera, + useCameraPermission, + useCameraDevice, + useCameraFormat, + PhotoFile, + VideoFile, + CameraRuntimeError, + Orientation, + // @ts-ignore +} from "react-native-vision-camera"; +import { RecordingButton } from "./capture-button"; +import { useIsForeground } from "./is-foreground"; import { useIsFocused } from '@react-navigation/native' - export default function CameraScreen(): React.ReactElement { - const camera = useRef(null) - const { hasPermission, requestPermission } = useCameraPermission() - const [isCameraInitialized, setIsCameraInitialized] = useState(false) + const camera = useRef(null); + const { hasPermission, requestPermission } = useCameraPermission(); + const [isCameraInitialized, setIsCameraInitialized] = + useState(false); - const isForeground = useIsForeground() + const isForeground = useIsForeground(); const isFocused = useIsFocused(); - const isActive = isForeground && isFocused + const isActive = isForeground && isFocused; const onError = useCallback((error: CameraRuntimeError) => { - console.error(error) - }, []) + console.error(error); + }, []); const onInitialized = useCallback(() => { - console.log('Camera initialized!') - setIsCameraInitialized(true) - }, []) + console.log("Camera initialized!"); + setIsCameraInitialized(true); + }, []); - const onMediaCaptured = useCallback( - (media: PhotoFile | VideoFile) => { - console.log(`Media captured! ${JSON.stringify(media)}`) - }, - [], - ) + const onMediaCaptured = useCallback((media: PhotoFile | VideoFile) => { + console.log(`Media captured! ${JSON.stringify(media)}`); + }, []); if (!hasPermission) { - requestPermission() + requestPermission(); // Error handling in case they refuse to give permission } - const device = useCameraDevice('back') + const device = useCameraDevice("back"); const format = useCameraFormat(device, [ { videoResolution: { width: 3048, height: 2160 } }, - { fps: 60 } - ]) + { fps: 60 }, + ]); // this sets as a target + + //Orientation detection + const [orientation, setOrientation] = useState("portrait"); + + const toggleOrientation = () => { + setOrientation( + (currentOrientation) => + currentOrientation === "landscape-left" ? "portrait" : "landscape-left", // Can adjust this and the type to match what we want + ); + }; if (device === null) { - return Camera not available. Does user have permissions: {hasPermission} + return ( + + Camera not available. Does user have permissions: {hasPermission} + + ); } - return ( hasPermission && ( @@ -57,30 +77,64 @@ export default function CameraScreen(): React.ReactElement { onInitialized={onInitialized} onError={onError} video={true} - photo={false} - orientation='portrait' // TODO: #60 + orientation={orientation} // TODO: #60 isActive={isActive} /> + +