FEATURE | Add voiceover text & fix bugs #8
Merged
Vitalik
merged 2 commits from voice-text
into main
10 months ago
38 changed files with 363 additions and 148 deletions
Binary file not shown.
Binary file not shown.
@ -1,2 +1,2 @@
@@ -1,2 +1,2 @@
|
||||
export * from './truth-or-dare-view' |
||||
export * from './truth-or-dare' |
||||
export * from './player-field.component'; |
||||
|
@ -1,53 +0,0 @@
@@ -1,53 +0,0 @@
|
||||
import React, { useEffect } from 'react' |
||||
import { Font, Icon, colors } from '../../common' |
||||
import { Animated, StyleSheet } from 'react-native' |
||||
import { useAnimationTruthOrDare } from '../animations' |
||||
|
||||
interface IProps { |
||||
item: string |
||||
} |
||||
|
||||
export const TruthOrDareView: React.FC<IProps> = ({ item }) => { |
||||
const { animStyle, startAnimation } = useAnimationTruthOrDare() |
||||
|
||||
useEffect(() => { |
||||
startAnimation() |
||||
}, []) |
||||
return ( |
||||
<Animated.View style={[styles.container, animStyle]}> |
||||
<Icon |
||||
name="magic-star" |
||||
size={24} |
||||
color={colors.turquoise} |
||||
style={styles.starIcon} |
||||
/> |
||||
<Animated.Text style={[styles.text]}>{item}</Animated.Text> |
||||
</Animated.View> |
||||
) |
||||
} |
||||
|
||||
const styles = StyleSheet.create({ |
||||
container: { |
||||
paddingHorizontal: 16, |
||||
paddingVertical: 32, |
||||
backgroundColor: colors.darkPurple, |
||||
borderRadius: 20, |
||||
alignItems: 'center', |
||||
shadowColor: '#190f42', |
||||
shadowOffset: { width: 0, height: 2 }, |
||||
shadowOpacity: 1, |
||||
shadowRadius: 4, |
||||
elevation: 5, |
||||
marginTop: 88, |
||||
}, |
||||
starIcon: { |
||||
marginBottom: 14, |
||||
}, |
||||
text: { |
||||
color: colors.purple, |
||||
fontSize: 22, |
||||
lineHeight: 32, |
||||
textAlign: 'center', |
||||
fontFamily: Font.Roboto400, |
||||
}, |
||||
}) |
@ -0,0 +1,104 @@
@@ -0,0 +1,104 @@
|
||||
import React, { useEffect, useState } from 'react' |
||||
import { Font, Icon, StorageKey, colors, storageService } from '../../common' |
||||
import { Animated, StyleSheet, View } from 'react-native' |
||||
import { useAnimationTruthOrDare } from '../animations' |
||||
import Tts from 'react-native-tts' |
||||
|
||||
interface IProps { |
||||
item: string |
||||
} |
||||
|
||||
export const TruthOrDare: React.FC<IProps> = ({ item }) => { |
||||
const wordsArr = item.trim().split(' ') |
||||
const [voiceover, setVoiceover] = useState(true) |
||||
|
||||
const { animStyle, animValues, startAnimationCard, startAnimTextByVoice } = |
||||
useAnimationTruthOrDare(wordsArr) |
||||
|
||||
useEffect(() => { |
||||
startAnimationCard() |
||||
|
||||
checkAndStartVoiceover() |
||||
}, [item]) |
||||
|
||||
const checkAndStartVoiceover = async () => { |
||||
const isVoicer = await storageService.get(StorageKey.Voiceover) |
||||
|
||||
setVoiceover(isVoicer) |
||||
|
||||
if (isVoicer) { |
||||
Tts.stop() |
||||
Tts.speak(item) |
||||
Tts.addEventListener('tts-start', startAnimTextByVoice) |
||||
} |
||||
} |
||||
|
||||
return ( |
||||
<Animated.View style={[styles.container, animStyle]}> |
||||
<Icon |
||||
name="magic-star" |
||||
size={24} |
||||
color={colors.turquoise} |
||||
style={styles.starIcon} |
||||
/> |
||||
<View style={styles.textWrap}> |
||||
{wordsArr?.map((word, index) => { |
||||
return ( |
||||
<Animated.Text |
||||
key={`${word} + ${index * word.length}`} |
||||
style={[ |
||||
styles.text, |
||||
{ |
||||
opacity: voiceover ? animValues[index] : 1, |
||||
transform: [ |
||||
{ |
||||
translateX: voiceover |
||||
? Animated.multiply( |
||||
animValues[index], |
||||
new Animated.Value(-5), |
||||
) |
||||
: 0, |
||||
}, |
||||
], |
||||
}, |
||||
]}> |
||||
{word + ' '} |
||||
</Animated.Text> |
||||
) |
||||
})} |
||||
</View> |
||||
</Animated.View> |
||||
) |
||||
} |
||||
|
||||
const styles = StyleSheet.create({ |
||||
container: { |
||||
paddingLeft: 21, |
||||
paddingRight: 11, |
||||
paddingVertical: 32, |
||||
backgroundColor: colors.darkPurple, |
||||
borderRadius: 20, |
||||
alignItems: 'center', |
||||
shadowColor: '#190f42', |
||||
shadowOffset: { width: 0, height: 2 }, |
||||
shadowOpacity: 1, |
||||
shadowRadius: 4, |
||||
elevation: 5, |
||||
marginTop: 88, |
||||
}, |
||||
textWrap: { |
||||
flexDirection: 'row', |
||||
flexWrap: 'wrap', |
||||
justifyContent: 'center', |
||||
}, |
||||
starIcon: { |
||||
marginBottom: 14, |
||||
}, |
||||
text: { |
||||
color: colors.purple, |
||||
fontSize: 22, |
||||
lineHeight: 32, |
||||
textAlign: 'center', |
||||
fontFamily: Font.Roboto400, |
||||
}, |
||||
}) |
@ -1 +1,2 @@
@@ -1 +1,2 @@
|
||||
export * from './package-name.config'; |
||||
export * from './voice.config'; |
||||
|
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
import { Language } from '~module/common' |
||||
|
||||
export const voiceConfig: any = { |
||||
[Language.UA]: { |
||||
language: 'uk-UA', |
||||
voice: 'com.apple.voice.compact.uk-UA.Lesya', |
||||
}, |
||||
[Language.EN]: { |
||||
language: 'en-US', |
||||
voice: 'com.apple.ttsbundle.Samantha-compact', |
||||
}, |
||||
} |
@ -1,2 +1,3 @@
@@ -1,2 +1,3 @@
|
||||
export * from './get-current-truth-dares.hook' |
||||
export * from './use-set-steps-by-package'; |
||||
export * from './use-voice.hook'; |
||||
|
@ -0,0 +1,42 @@
@@ -0,0 +1,42 @@
|
||||
import { useEffect, useState } from 'react' |
||||
import Tts from 'react-native-tts' |
||||
import { voiceConfig } from '../config' |
||||
import { useTranslation } from 'react-i18next' |
||||
|
||||
export const useVoice = () => { |
||||
const { i18n } = useTranslation() |
||||
const [ttsStatus, setTtsStatus] = useState('initiliazing') |
||||
|
||||
useEffect(() => { |
||||
Tts.addEventListener('tts-finish', _event => setTtsStatus('finished')) |
||||
Tts.addEventListener('tts-cancel', _event => setTtsStatus('cancelled')) |
||||
Tts.getInitStatus().then(initTts) |
||||
|
||||
return () => { |
||||
if (ttsStatus === 'finished') { |
||||
Tts.removeEventListener('tts-start', _event => |
||||
setTtsStatus('started'), |
||||
) |
||||
} |
||||
|
||||
Tts.removeEventListener('tts-finish', _event => |
||||
setTtsStatus('finished'), |
||||
) |
||||
Tts.removeEventListener('tts-cancel', _event => |
||||
setTtsStatus('cancelled'), |
||||
) |
||||
} |
||||
}, []) |
||||
|
||||
const initTts = async () => { |
||||
try { |
||||
await Tts.setDefaultLanguage(voiceConfig[i18n.language].language) |
||||
await Tts.setDefaultVoice(voiceConfig[i18n.language].voice) |
||||
await Tts.setDefaultRate(0.5) |
||||
} catch (err) { |
||||
//Samsung S9 has always this error:
|
||||
//"Language is not supported"
|
||||
console.log(`setDefaultLanguage error `, err) |
||||
} |
||||
} |
||||
} |
@ -1,3 +1,4 @@
@@ -1,3 +1,4 @@
|
||||
export * from './selected-language-in-settings.atom' |
||||
export * from './switch-notifications.atom' |
||||
export * from './purchases.atom' |
||||
export * from './switch-voiceover.atom'; |
||||
|
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
import React, { useEffect, useState } from 'react' |
||||
import { Switch } from 'react-native' |
||||
import { StorageKey, colors, storageService } from '../../common' |
||||
|
||||
export const SwitchVoiceoverAtom = () => { |
||||
const [voiceover, setVoiceover] = useState(true) |
||||
|
||||
const toggleSwitch = async () => { |
||||
setVoiceover(!voiceover) |
||||
await storageService.set(StorageKey.Voiceover, !voiceover) |
||||
} |
||||
|
||||
const getIsVoiceover = async () => { |
||||
const isVoiceover = await storageService.get(StorageKey.Voiceover) |
||||
|
||||
setVoiceover(isVoiceover) |
||||
} |
||||
|
||||
useEffect(() => { |
||||
getIsVoiceover() |
||||
}, []) |
||||
|
||||
return ( |
||||
<Switch |
||||
trackColor={{ true: colors.purple }} |
||||
thumbColor={voiceover ? colors.turquoise : colors.darkPurple} |
||||
ios_backgroundColor={colors.purple} |
||||
onValueChange={toggleSwitch} |
||||
style={{ width: 51 }} |
||||
value={voiceover} |
||||
/> |
||||
) |
||||
} |
Loading…
Reference in new issue