Browse Source

FEATURE | Add voiceover text

pull/8/head
Vlad Narizhnyi 10 months ago
parent
commit
6e94f58af4
  1. BIN
      android/app/src/main/assets/fonts/fontello.ttf
  2. 2
      ios/GoogleService-Info.plist
  3. 6
      ios/Podfile.lock
  4. 4
      ios/Truth.xcodeproj/project.pbxproj
  5. 11
      package-lock.json
  6. 1
      package.json
  7. BIN
      src/assets/resources/fonts/fontello.ttf
  8. 6
      src/config/fontello.json
  9. 1
      src/i18n/interfaces/settings.types.interface.ts
  10. 1
      src/i18n/locales/en/settings.translation.ts
  11. 2
      src/i18n/locales/ua/common.translation.ts
  12. 28
      src/module/common/questions-dares-list/questions-dares-list.ts
  13. 1
      src/module/common/typing/enums/storage-key.enum.ts
  14. 39
      src/module/game/animations/use-animation-truth-or-dare.hook.ts
  15. 67
      src/module/game/components/truth-or-dare-view.tsx
  16. 1
      src/module/game/config/index.ts
  17. 12
      src/module/game/config/voice.config.ts
  18. 12
      src/module/game/hooks/get-current-truth-dares.hook.tsx
  19. 1
      src/module/game/hooks/index.ts
  20. 42
      src/module/game/hooks/use-voice.hook.tsx
  21. 4
      src/module/game/screens/game.screen.tsx
  22. 24
      src/module/game/screens/truth-or-dare.screen.tsx
  23. 9
      src/module/root/screens/loading-screen.tsx
  24. 1
      src/module/settings/atoms/index.ts
  25. 2
      src/module/settings/atoms/switch-notifications.atom.tsx
  26. 33
      src/module/settings/atoms/switch-voiceover.atom.tsx
  27. 11
      src/module/settings/config/settings.config.tsx
  28. 2
      src/module/settings/screens/settings.screen.tsx

BIN
android/app/src/main/assets/fonts/fontello.ttf

Binary file not shown.

2
ios/GoogleService-Info.plist

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
<string>truth-or-dare-fcc54.appspot.com</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>ITSAppUsesNonExemptEncryption</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>

6
ios/Podfile.lock

@ -1286,6 +1286,8 @@ PODS: @@ -1286,6 +1286,8 @@ PODS:
- RNVectorIcons (9.2.0):
- React-Core
- SocketRocket (0.6.1)
- TextToSpeech (4.1.0):
- React
- Yoga (1.14.0)
- YogaKit (1.18.1):
- Yoga (~> 1.14)
@ -1368,6 +1370,7 @@ DEPENDENCIES: @@ -1368,6 +1370,7 @@ DEPENDENCIES:
- RNScreens (from `../node_modules/react-native-screens`)
- RNSVG (from `../node_modules/react-native-svg`)
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
- TextToSpeech (from `../node_modules/react-native-tts`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
@ -1503,6 +1506,8 @@ EXTERNAL SOURCES: @@ -1503,6 +1506,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-svg"
RNVectorIcons:
:path: "../node_modules/react-native-vector-icons"
TextToSpeech:
:path: "../node_modules/react-native-tts"
Yoga:
:path: "../node_modules/react-native/ReactCommon/yoga"
@ -1585,6 +1590,7 @@ SPEC CHECKSUMS: @@ -1585,6 +1590,7 @@ SPEC CHECKSUMS:
RNSVG: d7d7bc8229af3842c9cfc3a723c815a52cdd1105
RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
TextToSpeech: b3aa777ff5585705f179c0a2436bfd0926d1716e
Yoga: 4c3aa327e4a6a23eeacd71f61c81df1bcdf677d5
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a

4
ios/Truth.xcodeproj/project.pbxproj

@ -547,7 +547,7 @@ @@ -547,7 +547,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 2;
CURRENT_PROJECT_VERSION = 5;
DEVELOPMENT_TEAM = 7LY53JU2YB;
ENABLE_BITCODE = NO;
HEADER_SEARCH_PATHS = (
@ -616,7 +616,7 @@ @@ -616,7 +616,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 2;
CURRENT_PROJECT_VERSION = 5;
DEVELOPMENT_TEAM = 7LY53JU2YB;
HEADER_SEARCH_PATHS = (
"$(inherited)",

11
package-lock.json generated

@ -36,6 +36,7 @@ @@ -36,6 +36,7 @@
"react-native-splash-screen": "^3.3.0",
"react-native-svg": "^12.5.1",
"react-native-svg-transformer": "^1.0.0",
"react-native-tts": "^4.1.0",
"react-native-vector-icons": "^9.2.0",
"react-redux": "^9.0.4",
"validate.js": "^0.13.1"
@ -13517,6 +13518,11 @@ @@ -13517,6 +13518,11 @@
"react-native-svg": ">=12.0.0"
}
},
"node_modules/react-native-tts": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/react-native-tts/-/react-native-tts-4.1.0.tgz",
"integrity": "sha512-tvf3lQ6u9MqztUie37qoPw5YQPqi0ql1lPhDsBBs/RRA6A/H1J9X9H/qb1A0Hx0ZpjavrEdtVSqQQ2JDZvZCTQ=="
},
"node_modules/react-native-vector-icons": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-9.2.0.tgz",
@ -25487,6 +25493,11 @@ @@ -25487,6 +25493,11 @@
"path-dirname": "^1.0.2"
}
},
"react-native-tts": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/react-native-tts/-/react-native-tts-4.1.0.tgz",
"integrity": "sha512-tvf3lQ6u9MqztUie37qoPw5YQPqi0ql1lPhDsBBs/RRA6A/H1J9X9H/qb1A0Hx0ZpjavrEdtVSqQQ2JDZvZCTQ=="
},
"react-native-vector-icons": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-9.2.0.tgz",

1
package.json

@ -44,6 +44,7 @@ @@ -44,6 +44,7 @@
"react-native-splash-screen": "^3.3.0",
"react-native-svg": "^12.5.1",
"react-native-svg-transformer": "^1.0.0",
"react-native-tts": "^4.1.0",
"react-native-vector-icons": "^9.2.0",
"react-redux": "^9.0.4",
"validate.js": "^0.13.1"

BIN
src/assets/resources/fonts/fontello.ttf

Binary file not shown.

6
src/config/fontello.json

@ -293,6 +293,12 @@ @@ -293,6 +293,12 @@
"width": 1000
},
"search": ["clear"]
},
{
"uid": "572c9ded6a688698dc275b30ff30fefa",
"css": "music",
"code": 59406,
"src": "linecons"
}
]
}

1
src/i18n/interfaces/settings.types.interface.ts

@ -8,5 +8,6 @@ export namespace SettingLocale { @@ -8,5 +8,6 @@ export namespace SettingLocale {
share: string
policy: string
label: string
voiceover: string
}
}

1
src/i18n/locales/en/settings.translation.ts

@ -9,4 +9,5 @@ export const settingTranslation: SettingLocale.Core = { @@ -9,4 +9,5 @@ export const settingTranslation: SettingLocale.Core = {
share: 'Share app',
policy: 'Privacy policy',
label: 'What can we do to help?',
voiceover: 'Voiceover',
}

2
src/i18n/locales/ua/common.translation.ts

@ -7,7 +7,7 @@ const Validation = { @@ -7,7 +7,7 @@ const Validation = {
export const common: Common = {
validate: Validation,
shareMessage: 'Поділіться цим додатком зі своїми друзями',
shareMessage: 'Поділись цим додатком зі своїми друзями',
notFillPlayerTitle: 'Ой',
notFillPlayerMessage: 'Якесь поле не заповнене. Перевір будь ласка!',
helpAlertTitle: 'Добре!',

28
src/module/common/questions-dares-list/questions-dares-list.ts

@ -50,14 +50,14 @@ export const under18 = [ @@ -50,14 +50,14 @@ export const under18 = [
{
id: 9,
isDare: false,
en: 'Name a song that you are uncomfortable listening to in front of others',
ua: 'Назви пісню, яку тобі некомфортно слухати при інших',
en: 'Name a song that you are uncomfortable listening to in front of others.',
ua: 'Назви пісню, яку тобі некомфортно слухати при інших.',
},
{
id: 10,
isDare: true,
en: "Write 'Where's my beer' to your president on the social network ",
ua: 'Напиши "Де моє пиво" своєму президентові в соціальній мережі',
en: "Write 'Where's my beer' to your president on the social network.",
ua: 'Напиши "Де моє пиво" своєму президентові в соціальній мережі.',
},
{
id: 11,
@ -104,8 +104,8 @@ export const under18 = [ @@ -104,8 +104,8 @@ export const under18 = [
{
id: 18,
isDare: true,
en: 'Send a heartfelt message to the fifth person in your contact list, expressing gratitude for something',
ua: "Відправ сердечне повідомлення п'ятій людині у своєму списку контактів, висловлюючи вдячність за щось",
en: 'Send a heartfelt message to the fifth person in your contact list, expressing gratitude for something.',
ua: "Відправ сердечне повідомлення п'ятій людині у своєму списку контактів, висловлюючи вдячність за щось.",
},
{
id: 19,
@ -141,7 +141,7 @@ export const under18 = [ @@ -141,7 +141,7 @@ export const under18 = [
id: 24,
isDare: true,
en: 'Write an message with some hint to the person you like.',
ua: 'Напишіть повідомлення з натяком людині, яка вам подобається.',
ua: 'Напиши повідомлення з натяком людині, яка тобі подобається.',
},
{
id: 25,
@ -287,8 +287,8 @@ export const light = [ @@ -287,8 +287,8 @@ export const light = [
{
id: 7,
isDare: false,
en: 'If you could be invisible for a day, what would you do?',
ua: 'Якщо б ви могли бути невидимими на один день, Що б ти зробив(ла)?',
en: 'You have invisibility for one day. What would you do?',
ua: 'У тебе невидимість на один день. Що б ти зробив(ла)?',
},
{
id: 8,
@ -312,7 +312,7 @@ export const light = [ @@ -312,7 +312,7 @@ export const light = [
id: 11,
isDare: false,
en: 'What’s the most unusual place you’ve ever visited?',
ua: 'Яке найстрашніше місце, в якому ти був(ла)',
ua: 'Яке найстрашніше місце, в якому ти був(ла)?',
},
{
id: 12,
@ -347,8 +347,8 @@ export const light = [ @@ -347,8 +347,8 @@ export const light = [
{
id: 17,
isDare: false,
en: 'Tell the first impression when you saw the person on the left of you',
ua: 'Розкажи перше враження, коли ти побачив(ла) людину ліворуч віж тебе',
en: 'Tell the first impression when you saw the person on the left of you.',
ua: 'Розкажи перше враження, коли ти побачив(ла) людину ліворуч від тебе.',
},
{
id: 18,
@ -462,7 +462,7 @@ export const light = [ @@ -462,7 +462,7 @@ export const light = [
id: 34,
isDare: true,
en: 'Sit with an angry and sad face until the next round.',
ua: 'Сидіть зі злою та сумною міною до наступного раунда.',
ua: 'Сиди зі злою та сумною міною до наступного раунда.',
},
{
id: 35,
@ -603,7 +603,7 @@ export const crazy = [ @@ -603,7 +603,7 @@ export const crazy = [
id: 17,
isDare: true,
en: 'Act like a certain animal until your next turn. Others have to guess the animal.',
ua: 'Ведіть себе як собака до свого наступного ходу.',
ua: 'Веди себе як собака до свого наступного ходу.',
},
{
id: 18,

1
src/module/common/typing/enums/storage-key.enum.ts

@ -9,4 +9,5 @@ export enum StorageKey { @@ -9,4 +9,5 @@ export enum StorageKey {
Players = 'Players',
LimitForCrazy = 'limit',
SavedSteps = 'SavedSteps',
Voiceover = 'Voiceover',
}

39
src/module/game/animations/use-animation-truth-or-dare.hook.ts

@ -1,8 +1,40 @@ @@ -1,8 +1,40 @@
import { useRef } from 'react'
import { Animated } from 'react-native'
import { useTranslation } from 'react-i18next'
import { Animated, Platform } from 'react-native'
import { Language } from '~module/common'
export const useAnimationTruthOrDare = () => {
export const useAnimationTruthOrDare = (wordsArr: string[]) => {
const animContainer = useRef(new Animated.Value(400)).current
const { i18n } = useTranslation()
const animValues: Animated.Value[] = []
wordsArr.forEach((_, index) => (animValues[index] = new Animated.Value(0)))
const startAnimTextByVoice = (toValue = 1) => {
const animations = wordsArr.map((word, index) => {
const wordWithComma = word.includes(',')
const isEnLanguage = i18n.language === Language.EN
const duration = isEnLanguage ? 50 : 75
const durationWithComma = Platform.select({
android: 75,
default: isEnLanguage ? 175 : 100,
})
return Animated.timing(animValues[index], {
toValue,
duration:
word.length *
(wordWithComma ? durationWithComma : duration),
useNativeDriver: true,
})
})
Animated.sequence(animations).start()
}
const startAnimation = () => {
Animated.timing(animContainer, {
@ -20,8 +52,11 @@ export const useAnimationTruthOrDare = () => { @@ -20,8 +52,11 @@ export const useAnimationTruthOrDare = () => {
],
}
return {
startAnimation,
startAnimTextByVoice,
animValues,
animStyle: animStyleContainer,
}
}

67
src/module/game/components/truth-or-dare-view.tsx

@ -1,18 +1,38 @@ @@ -1,18 +1,38 @@
import React, { useEffect } from 'react'
import { Font, Icon, colors } from '../../common'
import { Animated, StyleSheet } from 'react-native'
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 TruthOrDareView: React.FC<IProps> = ({ item }) => {
const { animStyle, startAnimation } = useAnimationTruthOrDare()
export const TruthOrDare: React.FC<IProps> = ({ item }) => {
const wordsArr = item.trim().split(' ')
const [voiceover, setVoiceover] = useState(true)
const { animStyle, animValues, startAnimation, startAnimTextByVoice } =
useAnimationTruthOrDare(wordsArr)
useEffect(() => {
checkAndStartVoiceover()
startAnimation()
}, [])
}, [item])
const checkAndStartVoiceover = async () => {
const isVoicer = await storageService.get(StorageKey.Voiceover)
setVoiceover(isVoicer)
if (isVoicer) {
startAnimTextByVoice()
Tts.stop()
Tts.speak(item)
}
}
console.log('isVoiceover', voiceover)
return (
<Animated.View style={[styles.container, animStyle]}>
<Icon
@ -21,14 +41,40 @@ export const TruthOrDareView: React.FC<IProps> = ({ item }) => { @@ -21,14 +41,40 @@ export const TruthOrDareView: React.FC<IProps> = ({ item }) => {
color={colors.turquoise}
style={styles.starIcon}
/>
<Animated.Text style={[styles.text]}>{item}</Animated.Text>
<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: {
paddingHorizontal: 16,
paddingLeft: 21,
paddingRight: 11,
paddingVertical: 32,
backgroundColor: colors.darkPurple,
borderRadius: 20,
@ -40,6 +86,11 @@ const styles = StyleSheet.create({ @@ -40,6 +86,11 @@ const styles = StyleSheet.create({
elevation: 5,
marginTop: 88,
},
textWrap: {
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
},
starIcon: {
marginBottom: 14,
},

1
src/module/game/config/index.ts

@ -1 +1,2 @@ @@ -1 +1,2 @@
export * from './package-name.config';
export * from './voice.config';

12
src/module/game/config/voice.config.ts

@ -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',
},
}

12
src/module/game/hooks/get-current-truth-dares.hook.tsx

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import { useEffect } from 'react'
import { useEffect, useMemo } from 'react'
import {
resetStepsByTruthOrDare,
selectCustomPackage,
@ -64,8 +64,12 @@ export const useGetCurrentTruthOrDare = ({ @@ -64,8 +64,12 @@ export const useGetCurrentTruthOrDare = ({
return packageTruthsOrDares?.[currentStep]?.[i18n.language as Language]
}
const customTruthsOrDares = getGameItemsByCustomPackage()
const packageTruthsOrDares = getGameItemsByPackage()
const customTruthsOrDares = useMemo(getGameItemsByCustomPackage, [
customPackageShuffle,
customType,
])
const packageTruthsOrDares = useMemo(getGameItemsByPackage, [gameItems])
const currentItem = getCurrentItem()
const shuffleAndSavePackage = async () => {
@ -136,7 +140,7 @@ export const useGetCurrentTruthOrDare = ({ @@ -136,7 +140,7 @@ export const useGetCurrentTruthOrDare = ({
useEffect(() => {
checkIsNeedShuffle()
}, [currentStep, customTruthsOrDares])
}, [currentStep])
return currentItem
}

1
src/module/game/hooks/index.ts

@ -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';

42
src/module/game/hooks/use-voice.hook.tsx

@ -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'
import { StorageKey, storageService } from '~module/common'
export const useVoice = () => {
const { i18n } = useTranslation()
const [ttsStatus, setTtsStatus] = useState('initiliazing')
useEffect(() => {
Tts.addEventListener('tts-start', _event => setTtsStatus('started'))
Tts.addEventListener('tts-finish', _event => setTtsStatus('finished'))
Tts.addEventListener('tts-cancel', _event => setTtsStatus('cancelled'))
Tts.getInitStatus().then(initTts)
return () => {
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)
}
setTtsStatus('initialized')
}
}

4
src/module/game/screens/game.screen.tsx

@ -17,7 +17,7 @@ import { useIsFocused, useRoute } from '@react-navigation/native' @@ -17,7 +17,7 @@ import { useIsFocused, useRoute } from '@react-navigation/native'
import { useAnimationButton } from '../animations'
import { PlayerName } from '../components/player-name.component'
import { packageNameConfig } from '../config'
import { useSetStepsByPackage } from '../hooks'
import { useSetStepsByPackage, useVoice } from '../hooks'
interface IRouteParams {
packageType?: PackageType
@ -33,6 +33,8 @@ export const GameScreen: FC = () => { @@ -33,6 +33,8 @@ export const GameScreen: FC = () => {
useSetStepsByPackage(packageType)
useVoice()
const randomGame = () => {
const isTruthRandom = Math.random() < 0.5
const customRandom = isTruthRandom

24
src/module/game/screens/truth-or-dare.screen.tsx

@ -20,13 +20,14 @@ import { @@ -20,13 +20,14 @@ import {
onNextPlayer,
selectStep,
} from '../../../store/slices'
import { TruthOrDareView } from '../components'
import { TruthOrDare } from '../components'
import { useAnimationIconsButton } from '../animations'
import { useGetCurrentTruthOrDare } from '../hooks'
import { PlayerName } from '../components/player-name.component'
import { packageNameConfig } from '../config'
import { useTranslation } from 'react-i18next'
import { useDispatch, useSelector } from 'react-redux'
import Tts from 'react-native-tts'
interface IRouteParams {
packageType?: PackageType
@ -55,6 +56,7 @@ export const TruthOrDareScreen: React.FC = () => { @@ -55,6 +56,7 @@ export const TruthOrDareScreen: React.FC = () => {
dispatch(onNextPlayer())
dispatch(nextStep(choiceType))
saveLastStep()
Tts.stop()
}
const onAddGameItemToCustomPackage = () => {
@ -67,6 +69,7 @@ export const TruthOrDareScreen: React.FC = () => { @@ -67,6 +69,7 @@ export const TruthOrDareScreen: React.FC = () => {
}
const onPressAddPlus = () => {
Tts.stop()
const subtitleByChoice =
choiceType === ChoiceType.Truth
? t('customPack.addCustomTruth')
@ -157,7 +160,7 @@ export const TruthOrDareScreen: React.FC = () => { @@ -157,7 +160,7 @@ export const TruthOrDareScreen: React.FC = () => {
<View style={{ flex: 1 }}>
<PlayerName />
<TruthOrDareView item={currentItem} />
{currentItem ? <TruthOrDare item={currentItem} /> : null}
<View style={styles.buttons}>
<ButtonWithIcon
@ -175,14 +178,15 @@ export const TruthOrDareScreen: React.FC = () => { @@ -175,14 +178,15 @@ export const TruthOrDareScreen: React.FC = () => {
animation={animScale.func}
animStyle={animScale.style}
/>
<ButtonWithIcon
styleBtn={{ width: 101 }}
iconName="add-plus"
onPress={onPressAddPlus}
animation={animScale.func}
animStyle={animScale.style}
/>
{packageType !== PackageType.Custom && (
<ButtonWithIcon
styleBtn={{ width: 101 }}
iconName="add-plus"
onPress={onPressAddPlus}
animation={animScale.func}
animStyle={animScale.style}
/>
)}
</View>
</View>
</ScreenLayout>

9
src/module/root/screens/loading-screen.tsx

@ -31,6 +31,14 @@ export const LoadingScreen: FC = () => { @@ -31,6 +31,14 @@ export const LoadingScreen: FC = () => {
return await storageService.get(StorageKey.FinishOnBoarding)
}
const setVoiceover = async () => {
const isVoiceover = await storageService.get(StorageKey.Voiceover)
if (isVoiceover === null) {
await storageService.set(StorageKey.Voiceover, true)
}
}
const init = async () => {
const language = await getLanguage()
const isOnBoard = await getOnboardEnd()
@ -56,6 +64,7 @@ export const LoadingScreen: FC = () => { @@ -56,6 +64,7 @@ export const LoadingScreen: FC = () => {
useEffect(() => {
init()
setVoiceover()
}, [])
return (

1
src/module/settings/atoms/index.ts

@ -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';

2
src/module/settings/atoms/switch-notifications.atom.tsx

@ -6,7 +6,7 @@ export const SwitchNotificationsAtom = () => { @@ -6,7 +6,7 @@ export const SwitchNotificationsAtom = () => {
const [isEnabled, setIsEnabled] = useState(true)
const toggleSwitch = () => {
setIsEnabled(previousState => !previousState)
setIsEnabled(!isEnabled)
}
return (

33
src/module/settings/atoms/switch-voiceover.atom.tsx

@ -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}
/>
)
}

11
src/module/settings/config/settings.config.tsx

@ -1,6 +1,10 @@ @@ -1,6 +1,10 @@
import React from 'react'
import { SettingLocale } from '../../../i18n/interfaces/settings.types.interface'
import { SelectedLanguage, SwitchNotificationsAtom } from '../atoms'
import {
SelectedLanguage,
SwitchNotificationsAtom,
SwitchVoiceoverAtom,
} from '../atoms'
const translatePath = (itemKey: keyof SettingLocale.Core) =>
`settingTranslation.${itemKey}`
@ -20,6 +24,11 @@ export const settingsConfig = [ @@ -20,6 +24,11 @@ export const settingsConfig = [
image: 'notification',
component: () => <SwitchNotificationsAtom />,
},
{
title: translatePath('voiceover'),
image: 'music',
component: () => <SwitchVoiceoverAtom />,
},
{
title: translatePath('write'),
image: 'message',

2
src/module/settings/screens/settings.screen.tsx

@ -67,6 +67,8 @@ export const SettingsScreen: FC = () => { @@ -67,6 +67,8 @@ export const SettingsScreen: FC = () => {
break
case 'notification':
break
case 'voice':
break
case 'message':
nav.navigate(UserRouteKey.WriteToUs)
break

Loading…
Cancel
Save