add camera package

This commit is contained in:
Michele Balistreri 2024-09-30 12:52:23 +02:00
parent e910e0b6c4
commit 3853cf27e6
No known key found for this signature in database
GPG Key ID: E9567DA33A4F791A
10 changed files with 160 additions and 81 deletions

View File

@ -2,6 +2,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.NFC"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature
android:name="android.hardware.nfc.hce"

View File

@ -37,3 +37,5 @@ newArchEnabled=false
# Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead.
hermesEnabled=true
VisionCamera_enableCodeScanner=true

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View File

@ -1533,6 +1533,12 @@ PODS:
- secp256k1 (0.1.6)
- SocketRocket (0.7.0)
- SSZipArchive (2.4.3)
- VisionCamera (4.5.3):
- VisionCamera/Core (= 4.5.3)
- VisionCamera/React (= 4.5.3)
- VisionCamera/Core (4.5.3)
- VisionCamera/React (4.5.3):
- React-Core
- Yoga (0.0.0)
DEPENDENCIES:
@ -1605,6 +1611,7 @@ DEPENDENCIES:
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
- secp256k1 (from `https://github.com/status-im/secp256k1.swift.git`)
- SSZipArchive (= 2.4.3)
- VisionCamera (from `../node_modules/react-native-vision-camera`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
@ -1750,6 +1757,8 @@ EXTERNAL SOURCES:
secp256k1:
:git: https://github.com/status-im/secp256k1.swift.git
:submodules: true
VisionCamera:
:path: "../node_modules/react-native-vision-camera"
Yoga:
:path: "../node_modules/react-native/ReactCommon/yoga"
@ -1833,6 +1842,7 @@ SPEC CHECKSUMS:
secp256k1: f61d67e6fdcb85fd727acf1bf35ace6036db540c
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
VisionCamera: cb84d0d8485b3e67c91b62931d3aa88f49747c92
Yoga: 4ef80d96a5534f0e01b3055f17d1e19a9fc61b63
PODFILE CHECKSUM: d4103e04bbadf298531160a2567acefe236dd9f8

View File

@ -10,6 +10,8 @@
</array>
<key>NFCReaderUsageDescription</key>
<string>Enable Keycard</string>
<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) needs access to your Camera.</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>

89
package-lock.json generated
View File

@ -13,7 +13,8 @@
"react-native": "0.75.3",
"react-native-modal": "^13.0.1",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.6.0",
"react-native-vector-icons": "^10.1.0"
"react-native-vector-icons": "^10.1.0",
"react-native-vision-camera": "^4.5.3"
},
"devDependencies": {
"@babel/core": "^7.20.0",
@ -4775,9 +4776,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "22.5.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz",
"integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==",
"version": "22.7.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz",
"integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.19.2"
@ -4800,9 +4801,9 @@
"license": "MIT"
},
"node_modules/@types/react": {
"version": "18.3.8",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.8.tgz",
"integrity": "sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==",
"version": "18.3.10",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.10.tgz",
"integrity": "sha512-02sAAlBnP39JgXwkAq3PeU9DVaaGpZyF3MGcC0MKgQVkZor5IiiDAipVaxQHtDJAmO4GIy/rVBy/LzVj76Cyqg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@ -5729,9 +5730,9 @@
}
},
"node_modules/browserslist": {
"version": "4.23.3",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz",
"integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==",
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz",
"integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==",
"funding": [
{
"type": "opencollective",
@ -5748,8 +5749,8 @@
],
"license": "MIT",
"dependencies": {
"caniuse-lite": "^1.0.30001646",
"electron-to-chromium": "^1.5.4",
"caniuse-lite": "^1.0.30001663",
"electron-to-chromium": "^1.5.28",
"node-releases": "^2.0.18",
"update-browserslist-db": "^1.1.0"
},
@ -5880,9 +5881,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001663",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz",
"integrity": "sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA==",
"version": "1.0.30001664",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz",
"integrity": "sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g==",
"funding": [
{
"type": "opencollective",
@ -6652,9 +6653,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
"version": "1.5.27",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.27.tgz",
"integrity": "sha512-o37j1vZqCoEgBuWWXLHQgTN/KDKe7zwpiY5CPeq2RvUqOyJw9xnrULzZAEVQ5p4h+zjMk7hgtOoPdnLxr7m/jw==",
"version": "1.5.29",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.29.tgz",
"integrity": "sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw==",
"license": "ISC"
},
"node_modules/emittery": {
@ -7192,9 +7193,9 @@
}
},
"node_modules/eslint-plugin-react": {
"version": "7.36.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz",
"integrity": "sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA==",
"version": "7.37.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.0.tgz",
"integrity": "sha512-IHBePmfWH5lKhJnJ7WB1V+v/GolbB0rjS8XYVCSQCZKaQCAUhMoVoOEn1Ef8Z8Wf0a7l8KTJvuZg5/e4qrZ6nA==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -8047,9 +8048,9 @@
"license": "MIT"
},
"node_modules/flow-parser": {
"version": "0.246.0",
"resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.246.0.tgz",
"integrity": "sha512-WHRizzSrWFTcKo7cVcbP3wzZVhzsoYxoWqbnH4z+JXGqrjVmnsld6kBZWVlB200PwD5ur8r+HV3KUDxv3cHhOQ==",
"version": "0.247.1",
"resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.247.1.tgz",
"integrity": "sha512-DHwcm06fWbn2Z6uFD3NaBZ5lMOoABIQ4asrVA80IWvYjjT5WdbghkUOL1wIcbLcagnFTdCZYOlSNnKNp/xnRZQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
@ -13056,6 +13057,30 @@
"node": ">=10"
}
},
"node_modules/react-native-vision-camera": {
"version": "4.5.3",
"resolved": "https://registry.npmjs.org/react-native-vision-camera/-/react-native-vision-camera-4.5.3.tgz",
"integrity": "sha512-wulpS6ZY6SwuYMDD8csIFMFJ6lXeQq4bJvaAhwEnr0R9cZ53jDUs0/SFZva6UFEPIw64h0IdrrzuVTEufhDSgQ==",
"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/node_modules/@jest/types": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz",
@ -14224,9 +14249,9 @@
}
},
"node_modules/terser": {
"version": "5.33.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.33.0.tgz",
"integrity": "sha512-JuPVaB7s1gdFKPKTelwUyRq5Sid2A3Gko2S0PncwdBq7kN9Ti9HPWDQ06MPsEDGsZeVESjKEnyGy68quBk1w6g==",
"version": "5.34.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.34.1.tgz",
"integrity": "sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA==",
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
@ -14640,9 +14665,9 @@
}
},
"node_modules/update-browserslist-db": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
"integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz",
"integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==",
"funding": [
{
"type": "opencollective",
@ -14659,8 +14684,8 @@
],
"license": "MIT",
"dependencies": {
"escalade": "^3.1.2",
"picocolors": "^1.0.1"
"escalade": "^3.2.0",
"picocolors": "^1.1.0"
},
"bin": {
"update-browserslist-db": "cli.js"

View File

@ -16,7 +16,8 @@
"react-native": "0.75.3",
"react-native-modal": "^13.0.1",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.6.0",
"react-native-vector-icons": "^10.1.0"
"react-native-vector-icons": "^10.1.0",
"react-native-vision-camera": "^4.5.3"
},
"devDependencies": {
"@babel/core": "^7.20.0",

View File

@ -5,23 +5,26 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
import DiscoveryScreen from './components/steps/DiscoveryScreen';
import InitializationScreen from './components/steps/InitializationScreen';
import MnemonicScreen from './components/steps/MnemonicScreen';
import AuthenticationScreen from './components/steps/AuthenticationScreen';
import HomeScreen from './components/steps/HomeScreen';
import FactoryResetScreen from './components/steps/FactoryResetScreen';
import NFCModal from './NFCModal';
//@ts-ignore
import Keycard from "react-native-status-keycard";
import Dialpad from './components/Dialpad';
enum Step {
Discovery,
Initialization,
Loading,
Authentication,
Home,
FactoryReset,
}
const Main = () => {
const PIN_MAX_RETRY = 3;
const WALLET_DERIVATION_PATH = "m/84'/0'/0'/0/0";
const [isModalVisible, setIsModalVisible] = useState<boolean>(false);
const [step, setStep] = useState(Step.Discovery);
@ -32,6 +35,9 @@ const Main = () => {
const pinRef = useRef("");
const mnemonicRef = useRef("");
const isListeningCard = useRef(false);
const walletKey = useRef("");
const sessionId = useRef("")
const challenge = useRef("")
const getPairings = async () => {
const pairingJSON = await AsyncStorage.getItem("pairings");
@ -97,10 +103,10 @@ const Main = () => {
break;
case Step.Loading:
await Keycard.saveMnemonic(mnemonicRef.current, pinRef.current);
setStep(Step.Authentication);
break;
//fallthrough
case Step.Authentication:
setStep(Step.Discovery);
walletKey.current = await Keycard.exportKeyWithPath(pinRef.current, WALLET_DERIVATION_PATH);
setStep(Step.Home);
break;
case Step.FactoryReset:
await Keycard.factoryReset();
@ -195,6 +201,16 @@ const Main = () => {
return connectCard();
}
const authenticate = (pin: string) => {
pinRef.current = pin
connectCard();
return true;
}
const login = (sessionId: string, challenge: string) => {
}
const cancel = () => {
setStep(Step.Discovery);
}
@ -208,8 +224,9 @@ const Main = () => {
{step == Step.Discovery && <DiscoveryScreen onPressFunc={connectCard} onFactoryResetFunc={startFactoryReset}></DiscoveryScreen>}
{step == Step.Initialization && <InitializationScreen onPressFunc={initPin} onCancelFunc={cancel}></InitializationScreen>}
{step == Step.Loading && <MnemonicScreen pinRequired={pinRef.current ? false : true} pinRetryCounter={pinDisplayCounter()} onPressFunc={loadMnemonic} onCancelFunc={cancel}></MnemonicScreen>}
{step == Step.Authentication && <AuthenticationScreen pinRetryCounter={pinDisplayCounter()} onPressFunc={() => {} } onCancelFunc={cancel}></AuthenticationScreen>}
{step == Step.FactoryReset && <FactoryResetScreen pinRetryCounter={pinDisplayCounter()} onPressFunc={connectCard} onCancelFunc={cancel}></FactoryResetScreen>}
{step == Step.Authentication && <Dialpad pinRetryCounter={pinDisplayCounter()} prompt={"Choose PIN"} onCancelFunc={cancel} onNextFunc={authenticate}></Dialpad>}
{step == Step.Home && <HomeScreen walletKey={walletKey.current} onPressFunc={login} onCancelFunc={cancel}></HomeScreen>}
{step == Step.FactoryReset && <FactoryResetScreen pinRetryCounter={pinDisplayCounter()} onPressFunc={connectCard} onCancelFunc={cancel}></FactoryResetScreen>}
<NFCModal isVisible={isModalVisible} onChangeFunc={setIsModalVisible}></NFCModal>
</SafeAreaView>
);

View File

@ -1,41 +0,0 @@
import {FC } from "react";
import { StyleSheet, Text, View } from "react-native";
import Button from "../Button";
type AuthenticationScreenProps = {
pinRetryCounter: number;
onPressFunc: () => void;
onCancelFunc: () => void;
};
const AuthenticationScreen: FC<AuthenticationScreenProps> = props => {
const {pinRetryCounter, onPressFunc, onCancelFunc} = props;
return (
<View>
<View>
<Text style={styles.heading}> Success</Text>
<Text style={styles.prompt}>Work in progress...</Text>
<Button label="Home" disabled={false} btnColor="#199515" btnBorderColor="#199515" btnFontSize={17} btnBorderWidth={1} btnWidth="100%" onChangeFunc={onCancelFunc} btnJustifyContent='center'></Button>
</View>
</View>
)};
const styles = StyleSheet.create({
heading: {
textAlign: 'center',
fontSize: 30,
fontFamily: 'Inconsolata Medium',
color: '#199515',
marginTop: '50%'
},
prompt: {
textAlign: 'center',
fontSize: 18,
fontFamily: 'Inconsolata Regular',
color: 'white',
marginTop: '5%'
}
});
export default AuthenticationScreen;

View File

@ -0,0 +1,62 @@
import {FC, useEffect } from "react";
import { StyleSheet, Text, View } from "react-native";
import Button from "../Button";
import { useCameraDevice, useCameraPermission, useCodeScanner } from "react-native-vision-camera";
type HomeScreenProps = {
walletKey: string;
onPressFunc: (sessionId: string, challenge: string) => void;
onCancelFunc: () => void;
};
const HomeScreen: FC<HomeScreenProps> = props => {
const {walletKey, onPressFunc, onCancelFunc} = props;
const cameraDevice = useCameraDevice('back')
const { hasPermission, requestPermission } = useCameraPermission();
const codeScanner = useCodeScanner({
codeTypes: ['qr'],
onCodeScanned: (codes) => {
console.log(`Scanned ${codes.length} codes!`)
}
});
const walletAddress = () => {
return walletKey;
}
useEffect(() => {
if (!hasPermission) {
if (!requestPermission()) {
onCancelFunc();
};
}
});
return (
<View>
<View>
<Text style={styles.heading}> Success</Text>
<Text style={styles.prompt}>{walletAddress()}</Text>
<Button label="Home" disabled={false} btnColor="#199515" btnBorderColor="#199515" btnFontSize={17} btnBorderWidth={1} btnWidth="100%" onChangeFunc={onCancelFunc} btnJustifyContent='center'></Button>
</View>
</View>
)};
const styles = StyleSheet.create({
heading: {
textAlign: 'center',
fontSize: 30,
fontFamily: 'Inconsolata Medium',
color: '#199515',
marginTop: '50%'
},
prompt: {
textAlign: 'center',
fontSize: 18,
fontFamily: 'Inconsolata Regular',
color: 'white',
marginTop: '5%'
}
});
export default HomeScreen;