Skip to content

Commit

Permalink
feat(mobile): 💄 update learning flow
Browse files Browse the repository at this point in the history
Signed-off-by: Yunus Andréasson <yunus@edenmind.com>
  • Loading branch information
YunusAndreasson committed Oct 4, 2023
1 parent 4e07a6b commit 655fccd
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 48 deletions.
Binary file modified mobile/.yarn/install-state.gz
Binary file not shown.
Empty file.
4 changes: 3 additions & 1 deletion mobile/components/arabic-words.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ export default function ArabicWords({ sentence: { words }, currentPlayingWordInd
{
color: textColor,
fontSize: 55,
lineHeight
lineHeight,
paddingHorizontal: 5
}
]

Expand All @@ -85,6 +86,7 @@ export default function ArabicWords({ sentence: { words }, currentPlayingWordInd
bottom: -10,
color: theme.colors.tertiary,
fontSize: englishFontSize,
paddingHorizontal: 5,
position: 'absolute'
}
]
Expand Down
4 changes: 3 additions & 1 deletion mobile/components/context-highlighted.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ const WordsContextHighLighted = ({ arabicSentence, arabicWord, sentenceIsComplet
})

return (
<View style={{ direction: 'rtl', flexDirection: 'row', flexWrap: 'wrap', paddingTop: 50 }}>{renderWords()}</View>
<View style={{ direction: 'rtl', flexDirection: 'row', flexWrap: 'wrap', marginLeft: 7, paddingTop: 30 }}>
{renderWords()}
</View>
)
}

Expand Down
41 changes: 25 additions & 16 deletions mobile/components/english-arabic.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
/* eslint-disable unicorn/no-null */
import PropTypes from 'prop-types'
import React, { useState, useCallback } from 'react'
import { Text, useTheme, Divider, Surface } from 'react-native-paper'
import { Text, useTheme, Divider } from 'react-native-paper'

import ArabicWords from './arabic-words.js'
import PlaySound from './play-sound.js'
import { useSharedStyles } from '../styles/common.js'

export const EnglishArabic = ({ sentence: { arabic, english, words = [] } = {}, paddingBottom = 45 }) => {
export const EnglishArabic = ({
sentence: { arabic, english, words = [] } = {},
isPlaying,
setIsPlaying,
showRepeat,
setShowRepeat
}) => {
const theme = useTheme()
const sharedStyle = useSharedStyles(theme)

Expand All @@ -24,29 +30,29 @@ export const EnglishArabic = ({ sentence: { arabic, english, words = [] } = {},
}, [])

return (
<Surface
style={{
backgroundColor: theme.colors.elevation.level0,
flex: 1,
justifyContent: 'center'
}}
>
<>
<ArabicWords sentence={{ arabic, english, words }} currentPlayingWordIndex={currentPlayingWordIndex} />
<Divider style={sharedStyle.dividerHidden} />
<Text variant="bodyLarge" style={[sharedStyle.englishBody, { color: theme.colors.secondary }]}>
{english.charAt(0).toUpperCase() + english.slice(1)}
{showRepeat && english.charAt(0).toUpperCase() + english.slice(1)}
</Text>
<>
<Divider style={{ opacity: 0, paddingTop: 25 }} />
<PlaySound audioFileNames={fileNames} onPlayingWord={handlePlayingWord} onFinish={handlePlaybackFinished} />
<Divider style={{ opacity: 0, paddingBottom }} />
<PlaySound
audioFileNames={fileNames}
onPlayingWord={handlePlayingWord}
onFinish={handlePlaybackFinished}
isPlaying={isPlaying}
showRepeat={showRepeat}
setIsPlaying={setIsPlaying}
setShowRepeat={setShowRepeat}
/>
</>
</Surface>
</>
)
}

EnglishArabic.propTypes = {
paddingBottom: PropTypes.number,
isPlaying: PropTypes.bool.isRequired,
sentence: PropTypes.shape({
arabic: PropTypes.string.isRequired,
english: PropTypes.string.isRequired,
Expand All @@ -56,5 +62,8 @@ EnglishArabic.propTypes = {
filename: PropTypes.string.isRequired
})
)
}).isRequired
}).isRequired,
setIsPlaying: PropTypes.func.isRequired,
setShowRepeat: PropTypes.func.isRequired,
showRepeat: PropTypes.bool.isRequired
}
47 changes: 33 additions & 14 deletions mobile/components/play-sound.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,27 @@
/* eslint-disable nonblock-statement-body-position */
import * as Haptics from 'expo-haptics'
import PropTypes from 'prop-types'
import React, { useState, useCallback, useRef } from 'react'
import React, { useCallback, useRef, useEffect } from 'react'
import { Button, Text, useTheme } from 'react-native-paper'

import { useAudioPlayer } from '../hooks/use-audio-player.js'
import { useSharedStyles } from '../styles/common.js'

export default function PlaySound({ audioFileNames, onPlayingWord, onFinish }) {
export default function PlaySound({
audioFileNames,
onPlayingWord,
onFinish,
isPlaying,
setIsPlaying,
showRepeat,
setShowRepeat
}) {
const theme = useTheme()
const sharedStyle = useSharedStyles(theme)
const IS_PLAYING = true

const { playSound, stopSound } = useAudioPlayer()
const [isPlaying, setIsPlaying] = useState(false)
const buttonText = isPlaying ? 'STOP' : 'PLAY'
const buttonText = isPlaying ? 'STOP' : 'REPEAT'

const isCancelled = useRef(false)

Expand All @@ -33,10 +40,16 @@ export default function PlaySound({ audioFileNames, onPlayingWord, onFinish }) {
if (!onFinish) return

setIsPlaying(!IS_PLAYING)
setShowRepeat(true)
stopSound()
onFinish()
}, [IS_PLAYING, onFinish, stopSound])

// start playSounds when component is mounted
useEffect(() => {
playSounds()
}, [])

const playSounds = useCallback(async () => {
// Provide haptic feedback for the start of playback
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)
Expand Down Expand Up @@ -105,20 +118,26 @@ export default function PlaySound({ audioFileNames, onPlayingWord, onFinish }) {
}, [audioFileNames, handleSoundFinish, handleSequenceFinish, isPlaying, onPlayingWord, playSound, stopSound])

return (
<Button
onPress={playSounds}
style={{
...sharedStyle.buttonAnswer,
borderColor: isPlaying ? playingBorderColor : silentBorderColor
}}
>
<Text style={{ ...sharedStyle.actionTextPrimary }}>{buttonText}</Text>
</Button>
showRepeat && (
<Button
onPress={playSounds}
style={{
...sharedStyle.buttonAnswer,
borderColor: isPlaying ? playingBorderColor : silentBorderColor
}}
>
<Text style={{ ...sharedStyle.actionTextPrimary }}>{buttonText}</Text>
</Button>
)
)
}

PlaySound.propTypes = {
audioFileNames: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]).isRequired,
isPlaying: PropTypes.bool,
onFinish: PropTypes.func,
onPlayingWord: PropTypes.func
onPlayingWord: PropTypes.func,
setIsPlaying: PropTypes.func,
setShowRepeat: PropTypes.func,
showRepeat: PropTypes.bool
}
2 changes: 1 addition & 1 deletion mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"license": "MIT",
"homepage": "https://openarabic.io",
"repository": "https://github.com/edenmind/OpenArabic",
"version": "1445.2.372",
"version": "1445.2.373",
"authors": [
"Yunus Andreasson <yunus@edenmind.com> (https://github.com/YunusAndreasson)"
],
Expand Down
59 changes: 44 additions & 15 deletions mobile/screens/text-practice.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types'
import React, { useState, useEffect } from 'react'
import { View, ScrollView, StyleSheet } from 'react-native'
import { Surface, useTheme, Divider, ProgressBar } from 'react-native-paper'
import { useTheme, Divider, ProgressBar } from 'react-native-paper'

import { ActionButton } from '../components/action-button.js'
import { AnimatedButton } from '../components/animated-button.js'
Expand Down Expand Up @@ -39,6 +39,8 @@ const TextPractice = () => {
} = useTextPracticeLogic()

const [showWordsPractice, setShowWordsPractice] = useState(false)
const [isPlaying, setIsPlaying] = useState(false)
const [showRepeat, setShowRepeat] = useState(false)

useEffect(() => {
if (sentenceIsComplete) {
Expand Down Expand Up @@ -100,7 +102,11 @@ const TextPractice = () => {
handleContinue: handleStartPractice,
handleReset,
isLastSentence,
isPlaying,
setIsPlaying,
setSentenceIsComplete,
setShowRepeat,
showRepeat,
text
}}
/>
Expand All @@ -115,32 +121,55 @@ const SentenceControl = ({
text,
currentSentence,
isLastSentence,
isPlaying,
handleReset,
handleContinue,
setSentenceIsComplete
setIsPlaying,
setSentenceIsComplete,
showRepeat,
setShowRepeat
}) => (
<View style={{ bottom: 50, position: 'absolute', width: '100%' }}>
<EnglishArabic sentence={text.sentences[currentSentence]} paddingBottom={0} showAll={true} />
{isLastSentence ? (
<ActionButton onPress={handleReset} text="PRACTICE AGAIN" />
) : (
<ActionButton
onPress={() => {
handleContinue()
setSentenceIsComplete(false)
}}
text="CONTINUE"
<>
<View style={{ position: 'absolute', top: 150, width: '100%' }}>
<EnglishArabic
sentence={text.sentences[currentSentence]}
paddingBottom={0}
showAll={true}
isPlaying={isPlaying}
showRepeat={showRepeat}
setIsPlaying={setIsPlaying}
setShowRepeat={setShowRepeat}
/>
)}
</View>
</View>
<View style={{ bottom: 50, position: 'absolute', width: '100%' }}>
{isLastSentence ? (
<ActionButton onPress={handleReset} text="PRACTICE AGAIN" />
) : (
showRepeat && (
<ActionButton
onPress={() => {
handleContinue()
setSentenceIsComplete(false)
setShowRepeat(false)
}}
text="CONTINUE"
/>
)
)}
</View>
</>
)

SentenceControl.propTypes = {
currentSentence: PropTypes.number.isRequired,
handleContinue: PropTypes.func.isRequired,
handleReset: PropTypes.func.isRequired,
isLastSentence: PropTypes.bool.isRequired,
isPlaying: PropTypes.bool.isRequired,
setIsPlaying: PropTypes.func.isRequired,
setSentenceIsComplete: PropTypes.func.isRequired,
setShowRepeat: PropTypes.func.isRequired,
showRepeat: PropTypes.bool.isRequired,
text: PropTypes.object.isRequired
}

Expand Down

0 comments on commit 655fccd

Please sign in to comment.