1+ import { KeyboardAvoidingView , View , Text , TextInput , TouchableOpacity , StyleSheet , Platform } from 'react-native' ;
2+ import { useState , useEffect } from 'react' ;
3+ import { useAudioPlayer } from "expo-audio" ;
4+ import BackArrowComponent from '../components/BackArrowComponent' ;
5+ import { textToMorse , encodeMorse } from '../morse_util' ;
6+ import Fontisto from '@expo/vector-icons/Fontisto' ;
7+ import AntDesign from '@expo/vector-icons/AntDesign' ;
8+ import learnWords from '../assets/data/learnwords.json' ;
9+
10+ export default function learn ( ) {
11+ "use strict" ;
12+
13+ const [ words , setWords ] = useState ( null ) ;
14+ const [ morse , setMorse ] = useState ( "" ) ;
15+ const [ textInput , setTextInput ] = useState ( "" ) ;
16+ const [ isCorrect , setIsCorrect ] = useState ( false ) ;
17+ const player = useAudioPlayer ( ) ;
18+
19+ useEffect ( ( ) => {
20+ initWords ( ) ;
21+ } , [ ] ) ;
22+
23+ /**
24+ * Gets called after initialisation of the learning words, so that a first word is selected.
25+ */
26+ useEffect ( ( ) => {
27+ if ( words != null ) {
28+ getNextMorse ( ) ;
29+ }
30+ } , [ words ] ) ;
31+
32+ /**
33+ * Gets called everytime the user enters a new letter, checks whether the input is equal to the given morse code.
34+ */
35+ useEffect ( ( ) => {
36+ setIsCorrect ( morse != "" && textToMorse ( textInput ) === morse ) ;
37+ } , [ textInput ] ) ;
38+
39+ /**
40+ * Gets called every time a new morse message to find is set.
41+ * Requests to play the new morse code.
42+ */
43+ useEffect ( ( ) => {
44+ playMorse ( ) ;
45+ } , [ morse ] ) ;
46+
47+ /**
48+ * Initialises the useState which holds all learning words from the .josn file imported.
49+ */
50+ function initWords ( ) {
51+ setWords ( learnWords . words ) ;
52+ }
53+
54+ /**
55+ * Can only be called by the user when the correct word was entered.
56+ * Plays the morse code of the found word, resets the input and requests a new word to find.
57+ */
58+ function handleNextButton ( ) {
59+ setTextInput ( "" ) ;
60+ getNextMorse ( ) ;
61+ }
62+
63+ /**
64+ * Uses the audio player to play the morse code of the found word.
65+ */
66+ async function playMorse ( ) {
67+ player . seekTo ( 0 ) ;
68+ const uri = await encodeMorse ( morse , "last_learnword" )
69+ player . replace ( { uri : uri } ) ;
70+ player . play ( ) ;
71+ }
72+
73+ /**
74+ * Takes a random word of the learnword list and sets the corresponding useState.
75+ */
76+ function getNextMorse ( ) {
77+ setMorse ( textToMorse ( words . at ( Math . random ( ) * words . length ) ) ) ;
78+ }
79+
80+ return (
81+ < KeyboardAvoidingView behavior = { Platform . OS === 'ios' ? 'padding' : 'height' } style = { { flex : 1 , padding : 20 , paddingTop : 30 , gap : 20 } } >
82+ < BackArrowComponent > </ BackArrowComponent >
83+ < View style = { styles . morse_box_container } >
84+ < Text style = { styles . info_text } > Morse to Decode:</ Text >
85+ < View style = { styles . box_with_icon } >
86+ < Text style = { styles . morse_text } > { morse } </ Text >
87+ < Fontisto name = "question" size = { 45 } color = { 'black' } style = { styles . icon } > </ Fontisto >
88+ </ View >
89+ </ View >
90+ < View style = { styles . morse_box_container } >
91+ < Text style = { styles . info_text } > Your Input:</ Text >
92+ < View style = { styles . box_with_icon } >
93+ < Text style = { styles . morse_text } > { textToMorse ( textInput ) } </ Text >
94+ { ! isCorrect && < AntDesign name = "closecircleo" size = { 45 } color = { 'black' } style = { styles . icon } > </ AntDesign > }
95+ { isCorrect && < AntDesign name = "checkcircleo" size = { 45 } color = { 'black' } style = { styles . icon } > </ AntDesign > }
96+ </ View >
97+ </ View >
98+ < TextInput style = { styles . input } value = { textInput } onChangeText = { setTextInput } > </ TextInput >
99+ < TouchableOpacity style = { isCorrect ? styles . next_button : styles . next_button_disabled } disabled = { ! isCorrect } onPress = { ( ) => handleNextButton ( ) } >
100+ < Text style = { styles . next_button_text } > Next</ Text >
101+ </ TouchableOpacity >
102+ </ KeyboardAvoidingView >
103+ )
104+ }
105+
106+ const styles = StyleSheet . create ( {
107+ morse_box_container : {
108+ flexDirection : 'column'
109+ } ,
110+ box_with_icon : {
111+ flexDirection : 'row' ,
112+ columnGap : 10
113+ } ,
114+ icon : {
115+ alignSelf : 'center'
116+ } ,
117+ info_text : {
118+ fontSize : 20 ,
119+ alignSelf : 'flex-start'
120+ } ,
121+ morse_text : {
122+ fontSize : 30 ,
123+ borderWidth : 3 ,
124+ width : "80%" ,
125+ alignSelf : 'center' ,
126+ backgroundColor : 'lightgray'
127+ } ,
128+ input : {
129+ fontSize : 30 ,
130+ borderBottomWidth : 3 ,
131+ width : "80%" ,
132+ alignSelf : 'flex-start'
133+ } ,
134+ next_button : {
135+ backgroundColor : "green" ,
136+ borderRadius : 10 ,
137+ padding : 15 ,
138+ width : "50%" ,
139+ alignSelf : 'center'
140+ } ,
141+ next_button_disabled : {
142+ backgroundColor : "lightgray" ,
143+ borderRadius : 10 ,
144+ padding : 15 ,
145+ width : "50%" ,
146+ alignSelf : 'center'
147+ } ,
148+ next_button_text : {
149+ fontSize : 20.0 ,
150+ textAlign : "center"
151+ }
152+ } )
0 commit comments