initial import

This commit is contained in:
Ksenia Lebedeva 2024-09-11 19:07:54 +02:00
parent fa1f694e72
commit e65ade8ffe
10 changed files with 264 additions and 125 deletions

119
App.tsx
View File

@ -1,118 +1,9 @@
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
*/
import Main from './src//Main';
import React from 'react';
import type {PropsWithChildren} from 'react';
import {
SafeAreaView,
ScrollView,
StatusBar,
StyleSheet,
Text,
useColorScheme,
View,
} from 'react-native';
import {
Colors,
DebugInstructions,
Header,
LearnMoreLinks,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
type SectionProps = PropsWithChildren<{
title: string;
}>;
function Section({children, title}: SectionProps): React.JSX.Element {
const isDarkMode = useColorScheme() === 'dark';
const App = () => {
return (
<View style={styles.sectionContainer}>
<Text
style={[
styles.sectionTitle,
{
color: isDarkMode ? Colors.white : Colors.black,
},
]}>
{title}
</Text>
<Text
style={[
styles.sectionDescription,
{
color: isDarkMode ? Colors.light : Colors.dark,
},
]}>
{children}
</Text>
</View>
<Main></Main>
);
}
};
function App(): React.JSX.Element {
const isDarkMode = useColorScheme() === 'dark';
const backgroundStyle = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
};
return (
<SafeAreaView style={backgroundStyle}>
<StatusBar
barStyle={isDarkMode ? 'light-content' : 'dark-content'}
backgroundColor={backgroundStyle.backgroundColor}
/>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={backgroundStyle}>
<Header />
<View
style={{
backgroundColor: isDarkMode ? Colors.black : Colors.white,
}}>
<Section title="Step One">
Edit <Text style={styles.highlight}>App.tsx</Text> to change this
screen and then come back to see your edits.
</Section>
<Section title="See Your Changes">
<ReloadInstructions />
</Section>
<Section title="Debug">
<DebugInstructions />
</Section>
<Section title="Learn More">
Read the docs to discover what to do next:
</Section>
<LearnMoreLinks />
</View>
</ScrollView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
},
highlight: {
fontWeight: '700',
},
});
export default App;
export default App;

View File

@ -1,6 +1,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.NFC"/>
<uses-feature
android:name="android.hardware.nfc.hce"
android:required="true" />
<application
android:name=".MainApplication"

View File

@ -18,4 +18,36 @@ buildscript {
}
}
subprojects {
afterEvaluate {
if (project.hasProperty("android")) {
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
targetSdkVersion rootProject.ext.targetSdkVersion
}
// Speed up Tests Stage
tasks.withType(Test).configureEach {
// https://docs.gradle.org/current/userguide/performance.html#execute_tests_in_parallel
maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
// https://docs.gradle.org/current/userguide/performance.html#fork_tests_into_multiple_processes
forkEvery = 100
// https://docs.gradle.org/current/userguide/performance.html#disable_reports
reports.html.required = false
reports.junitXml.required = false
}
// Speed up Java Compile Stage
// https://docs.gradle.org/current/userguide/performance.html#run_the_compiler_as_a_separate_process
tasks.withType(JavaCompile).configureEach {
options.fork = true
}
}
}
}
}
apply plugin: "com.facebook.react.rootproject"

39
package-lock.json generated
View File

@ -1,15 +1,17 @@
{
"name": "keycardExit",
"name": "KeycardExit",
"version": "0.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "keycardExit",
"name": "KeycardExit",
"version": "0.0.1",
"dependencies": {
"react": "18.3.1",
"react-native": "0.75.2"
"react-native": "0.75.2",
"react-native-modal": "^13.0.1",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.5.39"
},
"devDependencies": {
"@babel/core": "^7.20.0",
@ -11344,7 +11346,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -11851,7 +11852,6 @@
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dev": true,
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
@ -11861,8 +11861,7 @@
"node_modules/prop-types/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==",
"dev": true
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/punycode": {
"version": "2.3.1",
@ -12018,6 +12017,32 @@
}
}
},
"node_modules/react-native-animatable": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/react-native-animatable/-/react-native-animatable-1.3.3.tgz",
"integrity": "sha512-2ckIxZQAsvWn25Ho+DK3d1mXIgj7tITkrS4pYDvx96WyOttSvzzFeQnM2od0+FUMzILbdHDsDEqZvnz1DYNQ1w==",
"dependencies": {
"prop-types": "^15.7.2"
}
},
"node_modules/react-native-modal": {
"version": "13.0.1",
"resolved": "https://registry.npmjs.org/react-native-modal/-/react-native-modal-13.0.1.tgz",
"integrity": "sha512-UB+mjmUtf+miaG/sDhOikRfBOv0gJdBU2ZE1HtFWp6UixW9jCk/bhGdHUgmZljbPpp0RaO/6YiMmQSSK3kkMaw==",
"dependencies": {
"prop-types": "^15.6.2",
"react-native-animatable": "1.3.3"
},
"peerDependencies": {
"react": "*",
"react-native": ">=0.65.0"
}
},
"node_modules/react-native-status-keycard": {
"version": "2.5.39",
"resolved": "git+ssh://git@github.com/status-im/react-native-status-keycard.git#93dd64754e676172310e6ea7187cc49f2dc013c6",
"license": "MPL 2.0"
},
"node_modules/react-native/node_modules/@jest/types": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz",

View File

@ -1,5 +1,5 @@
{
"name": "keycardExit",
"name": "KeycardExit",
"version": "0.0.1",
"private": true,
"scripts": {
@ -11,7 +11,9 @@
},
"dependencies": {
"react": "18.3.1",
"react-native": "0.75.2"
"react-native": "0.75.2",
"react-native-modal": "^13.0.1",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.5.39"
},
"devDependencies": {
"@babel/core": "^7.20.0",
@ -33,4 +35,4 @@
"engines": {
"node": ">=18"
}
}
}

60
src/Main.tsx Normal file
View File

@ -0,0 +1,60 @@
import React, { useEffect, useRef, useState } from 'react';
import { Platform, SafeAreaView, StyleSheet, useColorScheme, DeviceEventEmitter } from 'react-native';
import { Colors } from 'react-native/Libraries/NewAppScreen';
import StartScreen from './components/StartScreen';
//@ts-ignore
import Keycard from "react-native-status-keycard";
const Main = () => {
const isDarkMode = useColorScheme() === 'dark';
const [isModalVisible, setIsModalVisible] = useState<boolean>(false);
const didMount = useRef(false)
useEffect(() => {
if (!didMount.current) {
didMount.current = true;
DeviceEventEmitter.addListener("keyCardOnConnected", async () => {
console.log(await Keycard.getApplicationInfo());
setIsModalVisible(false);
});
DeviceEventEmitter.addListener("keyCardOnDisconnected", () => console.log("keycard disconnected"));
DeviceEventEmitter.addListener("keyCardOnNFCEnabled", () => console.log("nfc enabled"));
DeviceEventEmitter.addListener("keyCardOnNFCDisabled", () => console.log("nfc disabled"));
}
});
const backgroundStyle = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
};
const exitFunc = async () => {
if (await Keycard.nfcIsSupported() && !await Keycard.nfcIsEnabled()) {
await Keycard.openNfcSettings();
}
await Keycard.startNFC("Tap your Keycard");
if (Platform.OS === 'android') {
setIsModalVisible(true);
}
}
return (
<SafeAreaView style={[backgroundStyle, styles.container]}>
<StartScreen onExitBtnFunc={exitFunc} isModalVisible={isModalVisible} modalVisibilityFunc={setIsModalVisible}></StartScreen>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
paddingTop: '30%',
height: '100%',
paddingLeft: '6%',
paddingRight: '6%'
},
});
export default Main;

47
src/NFCModal.tsx Normal file
View File

@ -0,0 +1,47 @@
import React, {FC, useEffect, useState } from "react";
import {StyleSheet, Text, View } from "react-native";
import Modal from "react-native-modal/dist/modal";
type NFCModalProps = {
isVisible: boolean;
onChangeFunc: (val: boolean) => void;
};
const NFCModal: FC<NFCModalProps> = props => {
const {isVisible, onChangeFunc} = props;
return (
<Modal isVisible={isVisible} onSwipeComplete={() => onChangeFunc(!isVisible)} swipeDirection={['up', 'left', 'right', 'down']} style={modalStyle.modalContainer}>
<View style={modalStyle.container}>
<Text style={modalStyle.header}>Ready to Scan</Text>
<Text style={modalStyle.prompt}>Tap your Keycard</Text>
</View>
</Modal>
)};
const modalStyle = StyleSheet.create({
modalContainer: {
justifyContent: 'flex-end',
margin: 0
},
container: {
backgroundColor: '#4A646C',
height: 250,
paddingBottom: 20,
alignItems: 'center',
borderTopLeftRadius: 10,
borderTopRightRadius: 10,
borderColor: 'rgba(0, 0, 0, 0.1)',
},
header: {
paddingTop: '5%',
fontSize: 24
},
prompt: {
paddingTop: '10%',
paddingBottom: '10%',
fontSize: 15
}
});
export default NFCModal;

42
src/components/Button.tsx Normal file
View File

@ -0,0 +1,42 @@
import {FC } from "react";
import { DimensionValue, StyleSheet, Text, TouchableOpacity, View } from "react-native";
type ButtonProps = {
label: string;
disabled: boolean;
btnColor: string;
btnWidth: string;
btnJustifyContent: string;
onChangeFunc: () => void;
};
const Button: FC<ButtonProps> = props => {
const {label, disabled, btnColor, btnWidth, btnJustifyContent, onChangeFunc} = props;
return (
<View style={[buttonStyle.textBtnContainer, {width: btnWidth as DimensionValue, justifyContent: btnJustifyContent as any}]}>
<TouchableOpacity key={label} disabled={disabled} style={buttonStyle.button} onPress={onChangeFunc}>
<Text style={[buttonStyle.title, {color: btnColor}]}>{label}</Text>
</TouchableOpacity>
</View>
)};
const buttonStyle = StyleSheet.create({
textBtnContainer: {
flexDirection: 'row',
textAlign: 'center',
paddingTop: 25,
paddingBottom: 15,
justifyContent: 'flex-start'
},
button: {
},
title: {
fontSize: 15,
textTransform: 'uppercase',
},
});
export default Button;

View File

@ -0,0 +1,34 @@
import {FC } from "react";
import { StyleSheet, Text, View } from "react-native";
import NFCModal from "../NFCModal";
import Button from "./Button";
type StartScreenProps = {
onExitBtnFunc: () => void;
isModalVisible: boolean;
modalVisibilityFunc: (val: boolean) => void;
};
const StartScreen: FC<StartScreenProps> = props => {
const {onExitBtnFunc, isModalVisible, modalVisibilityFunc} = props;
return (
<View>
<View>
<Text style={styles.heading}> We are recruiting Operators to be the founders of a new, self-sovereign world in cyberspace</Text>
<Button label="Exit" disabled={false} btnColor="#4A646C" btnWidth="100%" onChangeFunc={onExitBtnFunc} btnJustifyContent='center'></Button>
</View>
<View>
<NFCModal isVisible={isModalVisible} onChangeFunc={modalVisibilityFunc}></NFCModal>
</View>
</View>
)};
const styles = StyleSheet.create({
heading: {
textAlign: 'center',
fontSize: 16
}
});
export default StartScreen;

View File

@ -1,3 +1,4 @@
{
"extends": "@react-native/typescript-config/tsconfig.json"
"extends": "@react-native/typescript-config/tsconfig.json",
"noImplicitAny": false
}