Browse Source
https://jetup-digital.atlassian.net/jira/software/projects/TRUT/boards/90?selectedIssue=TRUT-18 Co-authored-by: Vlad <vlad960706@gmail.com> Reviewed-on: #8 Co-authored-by: Vlad Narizhnyi <vlad960706@gmail.com> Co-committed-by: Vlad Narizhnyi <vlad960706@gmail.com>main^2
38 changed files with 363 additions and 148 deletions
Binary file not shown.
Binary file not shown.
@ -1,2 +1,2 @@ |
|||||||
export * from './truth-or-dare-view' |
export * from './truth-or-dare' |
||||||
export * from './player-field.component'; |
export * from './player-field.component'; |
||||||
|
@ -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 @@ |
|||||||
|
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 @@ |
|||||||
export * from './package-name.config'; |
export * from './package-name.config'; |
||||||
|
export * from './voice.config'; |
||||||
|
@ -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 @@ |
|||||||
export * from './get-current-truth-dares.hook' |
export * from './get-current-truth-dares.hook' |
||||||
export * from './use-set-steps-by-package'; |
export * from './use-set-steps-by-package'; |
||||||
|
export * from './use-voice.hook'; |
||||||
|
@ -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 @@ |
|||||||
export * from './selected-language-in-settings.atom' |
export * from './selected-language-in-settings.atom' |
||||||
export * from './switch-notifications.atom' |
export * from './switch-notifications.atom' |
||||||
export * from './purchases.atom' |
export * from './purchases.atom' |
||||||
|
export * from './switch-voiceover.atom'; |
||||||
|
@ -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