This commit is contained in:
Ivan Malison 2024-01-31 22:45:00 -07:00
parent 82069f3bef
commit 85b1cb8759
10 changed files with 301 additions and 126 deletions

View File

@ -1,10 +1,15 @@
rootProject.name = 'Railbird' rootProject.name = 'Railbird'
apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle"); apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle");
useExpoModules() 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"); 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) applyNativeModulesSettingsGradle(settings)
include ':app' include ':app'
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile()) includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile())
include ':react-native-vision-camera'
project(':react-native-vision-camera').projectDir = new File(rootProject.projectDir, '../react-native-vision-camera/package/android')

View File

@ -11,9 +11,7 @@
"resizeMode": "contain", "resizeMode": "contain",
"backgroundColor": "#ffffff" "backgroundColor": "#ffffff"
}, },
"assetBundlePatterns": [ "assetBundlePatterns": ["**/*"],
"**/*"
],
"plugins": [ "plugins": [
"@react-native-firebase/app", "@react-native-firebase/app",
"@react-native-firebase/auth", "@react-native-firebase/auth",

View File

@ -1,16 +1,34 @@
const path = require("path");
const pak = require("./react-native-vision-camera/package/package.json");
module.exports = function (api) { module.exports = function (api) {
api.cache(true); api.cache(true);
return { return {
presets: ["babel-preset-expo"], presets: ["babel-preset-expo"],
plugins: [ plugins: [
["module:react-native-dotenv", { [
"moduleName": "@env", "module:react-native-dotenv",
"path": ".env", {
"safe": false, moduleName: "@env",
"allowUndefined": true, path: ".env",
"verbose": false, safe: false,
}], allowUndefined: true,
'react-native-reanimated/plugin', verbose: false,
},
],
"react-native-reanimated/plugin",
[
"module-resolver",
{
alias: {
[pak.name]: path.join(
__dirname,
"./react-native-vision-camera/package",
pak.source,
),
},
},
],
], ],
}; };
}; };

View File

@ -1,57 +1,68 @@
import React, { useCallback, useRef, useState } from 'react' import React, { useCallback, useRef, useState } from "react";
import { Button, StyleSheet, Text, View } from 'react-native' import { Button, StyleSheet, Text, View } from "react-native";
import { Camera, useCameraPermission, useCameraDevice, useCameraFormat, PhotoFile, VideoFile, CameraRuntimeError, Orientation } from 'react-native-vision-camera' import {
import { RecordingButton } from './capture-button' Camera,
import { useIsForeground } from './is-foreground' useCameraPermission,
useCameraDevice,
useCameraFormat,
PhotoFile,
VideoFile,
CameraRuntimeError,
Orientation,
} from "react-native-vision-camera";
import { RecordingButton } from "./capture-button";
import { useIsForeground } from "./is-foreground";
export default function CameraScreen(): React.ReactElement { export default function CameraScreen(): React.ReactElement {
const camera = useRef<Camera>(null) const camera = useRef<Camera>(null);
const { hasPermission, requestPermission } = useCameraPermission() const { hasPermission, requestPermission } = useCameraPermission();
const [isCameraInitialized, setIsCameraInitialized] = useState<boolean>(false) const [isCameraInitialized, setIsCameraInitialized] =
useState<boolean>(false);
const isForeground: boolean = useIsForeground() const isForeground: boolean = useIsForeground();
const isActive: boolean = isForeground // Should be combined with isFocused hook const isActive: boolean = isForeground; // Should be combined with isFocused hook
const onError = useCallback((error: CameraRuntimeError) => { const onError = useCallback((error: CameraRuntimeError) => {
console.error(error) console.error(error);
}, []) }, []);
const onInitialized = useCallback(() => { const onInitialized = useCallback(() => {
console.log('Camera initialized!') console.log("Camera initialized!");
setIsCameraInitialized(true) setIsCameraInitialized(true);
}, []) }, []);
const onMediaCaptured = useCallback( const onMediaCaptured = useCallback((media: PhotoFile | VideoFile) => {
(media: PhotoFile | VideoFile) => { console.log(`Media captured! ${JSON.stringify(media)}`);
console.log(`Media captured! ${JSON.stringify(media)}`) }, []);
},
[],
)
if (!hasPermission) { if (!hasPermission) {
requestPermission() requestPermission();
// Error handling in case they refuse to give permission // Error handling in case they refuse to give permission
} }
const device = useCameraDevice('back') const device = useCameraDevice("back");
const format = useCameraFormat(device, [ const format = useCameraFormat(device, [
{ videoResolution: { width: 3048, height: 2160 } }, { videoResolution: { width: 3048, height: 2160 } },
{ fps: 60 } { fps: 60 },
]) // this sets as a target ]); // this sets as a target
//Orientation detection //Orientation detection
const [orientation, setOrientation] = useState<Orientation>('portrait'); const [orientation, setOrientation] = useState<Orientation>("portrait");
const toggleOrientation = () => { const toggleOrientation = () => {
setOrientation(currentOrientation => setOrientation(
currentOrientation === 'landscape-left' ? 'portrait' : 'landscape-left' // Can adjust this and the type to match what we want (currentOrientation) =>
currentOrientation === "landscape-left" ? "portrait" : "landscape-left", // Can adjust this and the type to match what we want
); );
}; };
if (device === null) { if (device === null) {
return <Text>Camera not available. Does user have permissions: {hasPermission}</Text> return (
<Text>
Camera not available. Does user have permissions: {hasPermission}
</Text>
);
} }
return ( return (
hasPermission && ( hasPermission && (
<View style={styles.container}> <View style={styles.container}>
@ -67,12 +78,22 @@ export default function CameraScreen(): React.ReactElement {
isActive={isActive} isActive={isActive}
/> />
<RecordingButton <RecordingButton
style={[styles.captureButton, orientation === 'portrait' ? styles.portrait : styles.landscape ]} style={[
styles.captureButton,
orientation === "portrait" ? styles.portrait : styles.landscape,
]}
camera={camera} camera={camera}
onMediaCaptured={onMediaCaptured} onMediaCaptured={onMediaCaptured}
enabled={isCameraInitialized} enabled={isCameraInitialized}
/> />
<View style={[styles.button, orientation === 'portrait' ? styles.togglePortrait : styles.toggleLandscape ]}> <View
style={[
styles.button,
orientation === "portrait"
? styles.togglePortrait
: styles.toggleLandscape,
]}
>
<Button <Button
title="Toggle Orientation" title="Toggle Orientation"
onPress={toggleOrientation} onPress={toggleOrientation}
@ -82,35 +103,35 @@ export default function CameraScreen(): React.ReactElement {
</View> </View>
</View> </View>
) )
) );
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
backgroundColor: 'black', backgroundColor: "black",
}, },
captureButton: { captureButton: {
position: 'absolute', position: "absolute",
alignSelf: 'center', alignSelf: "center",
}, },
button: { button: {
position: 'absolute', position: "absolute",
alignSelf: 'center', alignSelf: "center",
}, },
togglePortrait: { togglePortrait: {
bottom: 110, // needs refined bottom: 110, // needs refined
}, },
toggleLandscape: { toggleLandscape: {
transform: [{ rotate: '90deg' }], transform: [{ rotate: "90deg" }],
bottom: '43%', // Should come from SafeAreaProvider, hardcoded right now, should roughly appear above the button bottom: "43%", // Should come from SafeAreaProvider, hardcoded right now, should roughly appear above the button
left: 50 // needs refined left: 50, // needs refined
}, },
portrait: { portrait: {
bottom: 20 // needs refined bottom: 20, // needs refined
}, },
landscape: { landscape: {
bottom: '40%', // Should come from SafeAreaProvider bottom: "40%", // Should come from SafeAreaProvider
left: 20 // needs refined left: 20, // needs refined
} },
}) });

View File

@ -11,9 +11,15 @@
url = "github:tadfisher/android-nixpkgs"; url = "github:tadfisher/android-nixpkgs";
}; };
}; };
outputs = { self, nixpkgs, flake-utils, gitignore, android-nixpkgs, ... }: outputs = {
flake-utils.lib.eachDefaultSystem (system: self,
let nixpkgs,
flake-utils,
gitignore,
android-nixpkgs,
...
}:
flake-utils.lib.eachDefaultSystem (system: let
pkgs = import nixpkgs {inherit system;}; pkgs = import nixpkgs {inherit system;};
nodejs = pkgs.nodejs-18_x; nodejs = pkgs.nodejs-18_x;
# NOTE: this does not work # NOTE: this does not work
@ -38,7 +44,8 @@
runHook postInstall runHook postInstall
''; '';
}; };
android-sdk = android-nixpkgs.sdk.${system} (sdkPkgs: with sdkPkgs; [ android-sdk = android-nixpkgs.sdk.${system} (sdkPkgs:
with sdkPkgs; [
cmdline-tools-latest cmdline-tools-latest
build-tools-30-0-3 build-tools-30-0-3
build-tools-33-0-0 build-tools-33-0-0
@ -50,7 +57,8 @@
system-images-android-33-google-apis-x86-64 system-images-android-33-google-apis-x86-64
system-images-android-34-google-apis-x86-64 system-images-android-34-google-apis-x86-64
]); ]);
in with pkgs; { in
with pkgs; {
defaultPackage = appBuild; defaultPackage = appBuild;
devShell = mkShell { devShell = mkShell {
buildInputs = [nodejs yarn watchman gradle_7 alejandra nodePackages.prettier]; buildInputs = [nodejs yarn watchman gradle_7 alejandra nodePackages.prettier];
@ -58,7 +66,7 @@
shellHook = '' shellHook = ''
export JAVA_HOME=${pkgs.jdk17.home} export JAVA_HOME=${pkgs.jdk17.home}
source ${android-sdk.out}/nix-support/setup-hook source ${android-sdk.out}/nix-support/setup-hook
export PATH=${android-sdk}/bin:$PATH export PATH=${android-sdk}/bin:${android-sdk}/share/android-sdk/build-tools/33.0.0/:$PATH
ORG_GRADLE_PROJECT_ANDROID_HOME="$ANDROID_HOME" ORG_GRADLE_PROJECT_ANDROID_HOME="$ANDROID_HOME"
''; '';
}; };

View File

@ -384,7 +384,7 @@
); );
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG"; OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
PRODUCT_BUNDLE_IDENTIFIER = ai.railbird.railbird; PRODUCT_BUNDLE_IDENTIFIER = ai.railbird.railbird;
PRODUCT_NAME = Railbird; PRODUCT_NAME = "Railbird";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Railbird/Railbird-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Railbird/Railbird-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -419,7 +419,7 @@
); );
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE"; OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = ai.railbird.railbird; PRODUCT_BUNDLE_IDENTIFIER = ai.railbird.railbird;
PRODUCT_NAME = Railbird; PRODUCT_NAME = "Railbird";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Railbird/Railbird-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Railbird/Railbird-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;

View File

@ -1,7 +1,53 @@
// Learn more https://docs.expo.io/guides/customizing-metro const { getDefaultConfig } = require("expo/metro-config");
const { getDefaultConfig } = require('expo/metro-config'); const { mergeConfig } = require("@react-native/metro-config");
const path = require("path");
const escape = require("escape-string-regexp");
const exclusionList = require("metro-config/src/defaults/exclusionList");
const pak = require("./react-native-vision-camera/package/package.json");
/** @type {import('expo/metro-config').MetroConfig} */ const root = path.resolve(__dirname, "./react-native-vision-camera/package");
const config = getDefaultConfig(__dirname); const modules = Object.keys({ ...pak.peerDependencies });
const localPackagePath = path.resolve(
__dirname,
"./react-native-vision-camera/package/src/index",
);
module.exports = config; /**
* Metro configuration
* https://facebook.github.io/metro/docs/configuration
*
* @type {import('metro-config').MetroConfig}
*/
const config = {
watchFolders: [root],
// We need to make sure that only one version is loaded for peerDependencies
// So we block them at the root, and alias them to the versions in example's node_modules
resolver: {
blacklistRE: exclusionList(
modules.map(
(m) =>
new RegExp(`^${escape(path.join(root, "node_modules", m))}\\/.*$`),
),
),
extraNodeModules: modules.reduce(
(acc, name) => {
acc[name] = path.join(__dirname, "node_modules", name);
return acc;
},
{ "react-native-vision-camera": localPackagePath },
),
},
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true,
},
}),
},
};
module.exports = mergeConfig(getDefaultConfig(__dirname), config);

View File

@ -4,8 +4,8 @@
"main": "node_modules/expo/AppEntry.js", "main": "node_modules/expo/AppEntry.js",
"scripts": { "scripts": {
"start": "cp .env.development .env && expo start", "start": "cp .env.development .env && expo start",
"android": "expo start --android", "android": "expo run:android",
"ios": "expo start --ios", "ios": "expo run:ios",
"run:android": "expo run:android", "run:android": "expo run:android",
"run:ios": "expo run:ios", "run:ios": "expo run:ios",
"web": "expo start --web", "web": "expo start --web",
@ -54,8 +54,10 @@
"@babel/core": "^7.20.0", "@babel/core": "^7.20.0",
"@testing-library/jest-native": "^5.4.3", "@testing-library/jest-native": "^5.4.3",
"@testing-library/react-native": "^12.4.3", "@testing-library/react-native": "^12.4.3",
"@react-native/metro-config": "^0.72.9",
"@types/d3-path": "^3.0.2", "@types/d3-path": "^3.0.2",
"@types/jest": "^29.5.11", "@types/jest": "^29.5.11",
"metro-react-native-babel-preset": "^0.77.0",
"@types/react-native-svg-charts": "^5.0.16", "@types/react-native-svg-charts": "^5.0.16",
"eslint-config-prettier": "^9.1.0" "eslint-config-prettier": "^9.1.0"
}, },

View File

@ -1,10 +1,32 @@
{ {
"compilerOptions": { "compilerOptions": {
"allowJs": false,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"jsx": "react-native",
"lib": ["esnext"],
"module": "esnext",
"moduleResolution": "node",
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noStrictGenericChecks": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noUncheckedIndexedAccess": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"target": "esnext",
"outDir": "lib",
"paths": { "paths": {
"react-native-vision-camera": [ "react-native-vision-camera": [
"./react-native-vision-camera/package/src/index" "./react-native-vision-camera/package/src/index"
] ]
} }
}, },
"extends": "expo/tsconfig.base" "include": ["react-native-vision-camera/package/src", "."],
"exclude": ["node_modules"],
"extends": ["expo/tsconfig.base"]
} }

View File

@ -2487,6 +2487,16 @@
hermes-parser "0.15.0" hermes-parser "0.15.0"
nullthrows "^1.1.1" nullthrows "^1.1.1"
"@react-native/metro-config@^0.72.9":
version "0.72.11"
resolved "https://registry.yarnpkg.com/@react-native/metro-config/-/metro-config-0.72.11.tgz#c775a22fbb138cedd4513ca46c06bfd6a9dad316"
integrity sha512-661EyQnDdVelyc0qP/ew7kKkGAh6N6KlkuPLC2SQ8sxaXskVU6fSuNlpLW4bUTBUDFKG8gEOU2hp6rzk4wQnGQ==
dependencies:
"@react-native/js-polyfills" "^0.72.1"
metro-config "0.76.8"
metro-react-native-babel-transformer "0.76.8"
metro-runtime "0.76.8"
"@react-native/normalize-color@^2.0.0": "@react-native/normalize-color@^2.0.0":
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/@react-native/normalize-color/-/normalize-color-2.1.0.tgz#939b87a9849e81687d3640c5efa2a486ac266f91" resolved "https://registry.yarnpkg.com/@react-native/normalize-color/-/normalize-color-2.1.0.tgz#939b87a9849e81687d3640c5efa2a486ac266f91"
@ -7214,6 +7224,51 @@ metro-react-native-babel-preset@0.76.8:
babel-plugin-transform-flow-enums "^0.0.2" babel-plugin-transform-flow-enums "^0.0.2"
react-refresh "^0.4.0" react-refresh "^0.4.0"
metro-react-native-babel-preset@^0.77.0:
version "0.77.0"
resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.77.0.tgz#47457eca8e36b77156afbe790247a70dbb40faaa"
integrity sha512-HPPD+bTxADtoE4y/4t1txgTQ1LVR6imOBy7RMHUsqMVTbekoi8Ph5YI9vKX2VMPtVWeFt0w9YnCSLPa76GcXsA==
dependencies:
"@babel/core" "^7.20.0"
"@babel/plugin-proposal-async-generator-functions" "^7.0.0"
"@babel/plugin-proposal-class-properties" "^7.18.0"
"@babel/plugin-proposal-export-default-from" "^7.0.0"
"@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.0"
"@babel/plugin-proposal-numeric-separator" "^7.0.0"
"@babel/plugin-proposal-object-rest-spread" "^7.20.0"
"@babel/plugin-proposal-optional-catch-binding" "^7.0.0"
"@babel/plugin-proposal-optional-chaining" "^7.20.0"
"@babel/plugin-syntax-dynamic-import" "^7.8.0"
"@babel/plugin-syntax-export-default-from" "^7.0.0"
"@babel/plugin-syntax-flow" "^7.18.0"
"@babel/plugin-syntax-nullish-coalescing-operator" "^7.0.0"
"@babel/plugin-syntax-optional-chaining" "^7.0.0"
"@babel/plugin-transform-arrow-functions" "^7.0.0"
"@babel/plugin-transform-async-to-generator" "^7.20.0"
"@babel/plugin-transform-block-scoping" "^7.0.0"
"@babel/plugin-transform-classes" "^7.0.0"
"@babel/plugin-transform-computed-properties" "^7.0.0"
"@babel/plugin-transform-destructuring" "^7.20.0"
"@babel/plugin-transform-flow-strip-types" "^7.20.0"
"@babel/plugin-transform-function-name" "^7.0.0"
"@babel/plugin-transform-literals" "^7.0.0"
"@babel/plugin-transform-modules-commonjs" "^7.0.0"
"@babel/plugin-transform-named-capturing-groups-regex" "^7.0.0"
"@babel/plugin-transform-parameters" "^7.0.0"
"@babel/plugin-transform-react-display-name" "^7.0.0"
"@babel/plugin-transform-react-jsx" "^7.0.0"
"@babel/plugin-transform-react-jsx-self" "^7.0.0"
"@babel/plugin-transform-react-jsx-source" "^7.0.0"
"@babel/plugin-transform-runtime" "^7.0.0"
"@babel/plugin-transform-shorthand-properties" "^7.0.0"
"@babel/plugin-transform-spread" "^7.0.0"
"@babel/plugin-transform-sticky-regex" "^7.0.0"
"@babel/plugin-transform-typescript" "^7.5.0"
"@babel/plugin-transform-unicode-regex" "^7.0.0"
"@babel/template" "^7.0.0"
babel-plugin-transform-flow-enums "^0.0.2"
react-refresh "^0.4.0"
metro-react-native-babel-transformer@0.76.8: metro-react-native-babel-transformer@0.76.8:
version "0.76.8" version "0.76.8"
resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.8.tgz#c3a98e1f4cd5faf1e21eba8e004b94a90c4db69b" resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.8.tgz#c3a98e1f4cd5faf1e21eba8e004b94a90c4db69b"