diff --git a/react-native/package.json b/react-native/package.json
index c098499..66c06c6 100644
--- a/react-native/package.json
+++ b/react-native/package.json
@@ -16,7 +16,7 @@
"expo": "~44.0.0",
"expo-app-loading": "~1.3.0",
"expo-camera": "^12.1.2",
- "expo-font": "^10.0.5",
+ "expo-font": "~10.0.4",
"expo-status-bar": "~1.2.0",
"react": "17.0.1",
"react-dom": "17.0.1",
@@ -29,7 +29,8 @@
"react-navigation": "^4.4.4",
"react-navigation-stack": "^2.10.4",
"react-redux": "^7.2.6",
- "redux": "^4.1.2"
+ "redux": "^4.1.2",
+ "rn-swipeable-panel": "^1.2.7"
},
"devDependencies": {
"@babel/core": "^7.12.9",
diff --git a/react-native/screens/TranslateScreen.tsx b/react-native/screens/TranslateScreen.tsx
index f024ec1..fdc99aa 100644
--- a/react-native/screens/TranslateScreen.tsx
+++ b/react-native/screens/TranslateScreen.tsx
@@ -1,14 +1,45 @@
-import React, { useState, useEffect } from 'react';
-import { StyleSheet, Text, View, TouchableOpacity, ImageBackground } from 'react-native';
+import React, { useState, useEffect, useCallback } from 'react';
+import { StyleSheet, Text, View, ScrollView, TouchableOpacity, TouchableHighlight, ImageBackground, Dimensions } from 'react-native';
import { Camera } from 'expo-camera';
-import { Ionicons } from '@expo/vector-icons';
+import { Ionicons, Entypo, FontAwesome, MaterialIcons } from '@expo/vector-icons';
+import { SwipeablePanel } from 'rn-swipeable-panel';
import { theme } from '../core/theme';
+import type { Navigation } from '../types';
+import AppLoading from 'expo-app-loading';
+import useFonts from '../hooks/useFonts'
-export default function TranslateScreen() {
+
+const NO_WIDTH_SPACE = '';
+const highlight = (text: string) =>
+ text.split(' ').map((word, i) => (
+
+ {word}
+ {NO_WIDTH_SPACE}
+
+ ));
+
+export default function TranslateScreen({ navigation }: Navigation) {
const [hasPermission, setHasPermission] = useState(false);
+ const [fontsLoaded, SetFontsLoaded] = useState(false);
const [type, setType] = useState(Camera.Constants.Type.back);
const [camera, setCamera] = useState(null);
const [imageUri, setImageUri] = useState("");
+ const [results, setResults] = useState<{"content": string; "underline": boolean}[]>();
+ const [fullText, setFullText] = useState<{"translated": string; "korean": string}>();
+ const [showFullText, setShowFullText] = useState(false);
+ const [showTranslated, setShowTranslated] = useState(true);
+ const [panelProps, setPanelProps] = useState({
+ fullWidth: true,
+ openLarge: false,
+ onlyLarge: false,
+ smallPanelHeight: Dimensions.get('window').height*0.6,
+ onClose: () => {}
+ })
+ const [loaded, setLoaded] = useState(0);
+
+ const LoadFontsAndRestoreToken = async () => {
+ await useFonts();
+ };
useEffect(() => {
(async () => {
@@ -24,6 +55,16 @@ export default function TranslateScreen() {
return No access to camera!
}
+ if (!fontsLoaded) {
+ return (
+ SetFontsLoaded(true)}
+ onError={() => {}}
+ />
+ );
+ }
+
const takePicture = async () => {
if (camera) {
const data = await camera.takePictureAsync(null);
@@ -32,47 +73,152 @@ export default function TranslateScreen() {
}
};
+ const extractText = () => {
+ // TODO: api
+ // TEST
+ setResults([
+ {"content": "Buy Suyeon a delicious meal.", "underline": false},
+ {"content": "The graduation ceremony will be held in the auditorium at 2 p.m. on February 14th.", "underline": true},
+ ]);
+ setFullText({
+ "translated": "You have to buy Suyeon a delicious meal. Hee is writing ... The graduation ceremony will be held in the auditorium at 2 p.m. on February 14th. We look forward to your involvement! You have to buy Suyeon a delicious meal. Hee is writing ... The graduation ceremony will be held in the auditorium at 2 p.m. on February 14th. We look forward to your involvement! You have to buy Suyeon a delicious meal. Hee is writing ... The graduation ceremony will be held in the auditorium at 2 p.m. on February 14th. We look forward to your involvement!",
+ "korean": "수연이에게 맛있는 밥을 사야합니다. 희가 쓰는 중... 졸업식은 2월 14일에 강당에서 열릴 예정입니다. 많은 참여 부탁드립니다!"
+ });
+ }
+
+ const handleFullText = () => {
+ setShowFullText(!showFullText);
+ setPanelProps({...panelProps, openLarge: !panelProps.openLarge, onlyLarge: !panelProps.onlyLarge});
+ // setPanelProps({...panelProps, onlyLarge: !panelProps.onlyLarge});
+ }
+
+ const saveResults = () => {
+ // TODO: api
+ console.log("save");
+ alert('saved');
+ }
+
+ const handleTranslatedText = () => {
+ setShowTranslated(!showTranslated);
+ }
+
+ const closeResults = () => {
+ navigation.navigate('Home');
+ }
+
const retakePicture = () => {
- setImageUri("");
+ setImageUri('');
+ setResults([]);
+ setFullText({ "translated": "", "korean": "" });
+ setShowFullText(false);
+ setPanelProps({...panelProps, openLarge: false});
}
return (
+ {/* After taking a picture */}
{imageUri ? (
- <>
-
-
-
-
-
-
- >
+ /* After taking a picture and press the check button */
+ results && results.length > 0 ? (
+
+
+
+
+
+ {showFullText ? "Full Text" : "Results"}
+ {!showFullText ? (
+
+
+
+
+
+
+
+
+ ) : (
+
+
+
+ )}
+
+
+
+ {!showFullText ? (
+ results.map((result, index) =>
+
+ {index+1}.
+ {result.underline ? (
+ highlight(result.content)
+ ) : (
+ result.content
+ )}
+
+ )
+ ) : (
+ showTranslated ? (
+ {fullText?.translated}
+ ) : (
+ {fullText?.korean}
+ )
+ )}
+
+
+
+ {!showFullText ? (
+
+ Close
+
+ ) : (
+
+ Back
+
+ )}
+
+
+ Try again
+
+
+
+
+
+ ) : (
+ /* After taking a picture, before OCR(pressing the check button) */
+ <>
+
+
+
+
+
+
+ >
+ )
) : (
+ /* Before taking a picture, Camera ready */
<>
setCamera(ref)}>
- {
- setType(
- type === Camera.Constants.Type.back
- ? Camera.Constants.Type.front
- : Camera.Constants.Type.back
- );
- }}>
-
+ {
+ setType(
+ type === Camera.Constants.Type.back
+ ? Camera.Constants.Type.front
+ : Camera.Constants.Type.back
+ );
+ }}>
+
-
-
+
+
>
)}
- );
+ );
}
const styles = StyleSheet.create({
@@ -88,7 +234,7 @@ const styles = StyleSheet.create({
flexDirection: 'row',
margin: 20,
},
- button: {
+ reverseButton: {
flex: 0.1,
alignSelf: 'flex-end',
alignItems: 'center',
@@ -98,10 +244,79 @@ const styles = StyleSheet.create({
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
+ backgroundColor: '#000'
},
- captureButton: {
- backgroundColor: theme.colors.primary,
+ circleButton: {
borderRadius: 48,
- padding: 8
+ height: 64,
+ width: 64,
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ primaryBackground: {
+ backgroundColor: theme.colors.primary
+ },
+ grayBackground: {
+ backgroundColor: theme.colors.gray
+ },
+ whiteText: {
+ color: '#fff',
+ fontSize: 16
+ },
+ whiteBackground: {
+ backgroundColor: '#fff',
+ },
+ regularButton: {
+ paddingVertical: 16,
+ flex: 0.9,
+ marginTop: 16,
+ alignItems: 'center',
+ borderRadius: 16
+ },
+ gap: {
+ flex: 0.1
+ },
+ innerCircle: {
+ borderRadius: 48,
+ padding: 8,
+ height: 56,
+ width: 56,
+ borderWidth: 2
+ },
+ bottomDrawer: {
+ flex: 1,
+ height: Dimensions.get('window').height*0.5,
+ flexDirection: 'column',
+ alignContent: 'space-between',
+ backgroundColor: theme.colors.background,
+ borderTopLeftRadius: 48,
+ borderTopRightRadius: 48,
+ padding: 32
+ },
+ title: {
+ fontFamily: 'Lora_700Bold',
+ fontSize: 24,
+ fontWeight: '700',
+ color: theme.colors.primary,
+ },
+ content: {
+ fontSize: 16,
+ paddingBottom: 8
+ },
+ spaceBetween: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ paddingBottom: 24
+ },
+ alignRow: {
+ flexDirection: 'row'
+ },
+ rightSpace: {
+ paddingRight: 8
+ },
+ highlighted: {
+ backgroundColor: theme.colors.skyblue
}
});
\ No newline at end of file
diff --git a/react-native/yarn.lock b/react-native/yarn.lock
index e7828dc..3d0098d 100644
--- a/react-native/yarn.lock
+++ b/react-native/yarn.lock
@@ -2726,7 +2726,7 @@ expo-file-system@~13.1.3:
"@expo/config-plugins" "^4.0.2"
uuid "^3.4.0"
-expo-font@^10.0.5, expo-font@~10.0.5:
+expo-font@~10.0.4, expo-font@~10.0.5:
version "10.0.5"
resolved "https://registry.npmjs.org/expo-font/-/expo-font-10.0.5.tgz"
integrity sha512-x9YwM0xLkDdSvFjeNbyuh33Q1Hk3uc2jbMuuAN5W2ZVcUZqG0M8GCX/KV/D/7rYqdXKbliQA5r44MyDwZe/XRw==
@@ -5044,6 +5044,13 @@ rimraf@~2.2.6:
resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz"
integrity sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=
+rn-swipeable-panel@^1.2.5, rn-swipeable-panel@^1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/rn-swipeable-panel/-/rn-swipeable-panel-1.2.7.tgz#a72f65c91d51715e84cdb9e912db8d94c150b1be"
+ integrity sha512-ibaU2+4J/VliCud8neQLzuLLNv3DP3t3+ySeG6Nn4mibhLQp/lvU47lCzvPiz4WhO6FTzre2k7Q5LqsuH5ThXQ==
+ dependencies:
+ rn-swipeable-panel "^1.2.5"
+
rsvp@^4.8.4:
version "4.8.5"
resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz"