Skip to content

Commit

Permalink
feat(mobile-app): play sound (#6)
Browse files Browse the repository at this point in the history
re #4
  • Loading branch information
sneas authored Feb 16, 2024
1 parent f21050d commit 2fbf97e
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 25 deletions.
2 changes: 1 addition & 1 deletion mobile-app/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.7
1.8
4 changes: 2 additions & 2 deletions mobile-app/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ android {
applicationId "com.vocablypro"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 6
versionName "1.6"
versionCode 9
versionName "1.8"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()

if (isNewArchitectureEnabled()) {
Expand Down
9 changes: 9 additions & 0 deletions mobile-app/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,11 @@ PODS:
- RNScreens (3.18.2):
- React-Core
- React-RCTImage
- RNSound (0.11.2):
- React-Core
- RNSound/Core (= 0.11.2)
- RNSound/Core (0.11.2):
- React-Core
- RNVectorIcons (9.2.0):
- React-Core
- SocketRocket (0.6.0)
Expand Down Expand Up @@ -500,6 +505,7 @@ DEPENDENCIES:
- RNInAppBrowser (from `../node_modules/react-native-inappbrowser-reborn`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
- RNScreens (from `../node_modules/react-native-screens`)
- RNSound (from `../node_modules/react-native-sound`)
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)

Expand Down Expand Up @@ -612,6 +618,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-reanimated"
RNScreens:
:path: "../node_modules/react-native-screens"
RNSound:
:path: "../node_modules/react-native-sound"
RNVectorIcons:
:path: "../node_modules/react-native-vector-icons"
Yoga:
Expand Down Expand Up @@ -676,6 +684,7 @@ SPEC CHECKSUMS:
RNInAppBrowser: e36d6935517101ccba0e875bac8ad7b0cb655364
RNReanimated: ce445c233a6ff5600223484a88ad5704945d972a
RNScreens: 34cc502acf1b916c582c60003dc3089fa01dc66d
RNSound: 6c156f925295bdc83e8e422e7d8b38d33bc71852
RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8
SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
Yoga: 445485143df46a9d5d4ef61cbbc629fec40fb9a0
Expand Down
4 changes: 2 additions & 2 deletions mobile-app/ios/VocablyPro.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1.7;
CURRENT_PROJECT_VERSION = 1.8;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 789D8NRAM6;
ENABLE_BITCODE = NO;
Expand Down Expand Up @@ -566,7 +566,7 @@
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1.7;
CURRENT_PROJECT_VERSION = 1.8;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 789D8NRAM6;
INFOPLIST_FILE = VocablyPro/Info.plist;
Expand Down
4 changes: 2 additions & 2 deletions mobile-app/ios/VocablyPro/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.7</string>
<string>1.8</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
Expand All @@ -30,7 +30,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.7</string>
<string>1.8</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>
Expand Down
4 changes: 2 additions & 2 deletions mobile-app/ios/VocablyProTests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.7</string>
<string>1.8</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.7</string>
<string>1.8</string>
</dict>
</plist>
15 changes: 15 additions & 0 deletions mobile-app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions mobile-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"react-native-reanimated": "^2.13.0",
"react-native-safe-area-context": "^4.4.1",
"react-native-screens": "^3.18.2",
"react-native-sound": "^0.11.2",
"react-native-vector-icons": "^9.2.0"
},
"devDependencies": {
Expand Down
17 changes: 15 additions & 2 deletions mobile-app/src/CardListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Card, CardItem } from '@vocably/model';
import { Card, CardItem, GoogleLanguage } from '@vocably/model';
import React, { FC } from 'react';
import { StyleProp, View, ViewStyle } from 'react-native';
import { Divider, Text, useTheme } from 'react-native-paper';
import { PlaySound } from './PlaySound';
import { SideB } from './SideB';
import { mainPadding } from './styles';

Expand Down Expand Up @@ -29,9 +30,21 @@ export const CardListItem: CardListItem = ({ card, style }) => {
alignItems: 'baseline',
}}
>
<Text style={{ fontSize: 24, color: theme.colors.secondary }}>
<PlaySound
text={card.source}
language={card.language as GoogleLanguage}
size={22}
style={{ marginRight: 6 }}
/>
<Text
style={{
fontSize: 24,
color: theme.colors.secondary,
}}
>
{card.source}
</Text>

{card.partOfSpeech && (
<Text style={{ marginLeft: 8 }}>{card.partOfSpeech}</Text>
)}
Expand Down
77 changes: 77 additions & 0 deletions mobile-app/src/PlaySound.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { GoogleLanguage } from '@vocably/model';
import React, { FC, useCallback, useEffect, useState } from 'react';
import { Alert, Pressable, StyleProp, ViewStyle } from 'react-native';
import { useTheme } from 'react-native-paper';
import Sound from 'react-native-sound';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';

type PlaySound = FC<{
text: string;
language: GoogleLanguage;
size?: number;
style?: StyleProp<ViewStyle>;
}>;

export const PlaySound: PlaySound = ({
text,
language,
size = 16,
style = {},
}) => {
const theme = useTheme();

const [isPlaying, setIsPlaying] = useState(false);
const [loadedAudio, setLoadedAudio] = useState<Sound | null>(null);

const playSound = useCallback(() => {
const audio =
loadedAudio ??
new Sound(
`https://translate.google.com/translate_tts?ie=UTF-8&q=${text}&tl=${language}&client=tw-ob`,
'',
(error) => {
if (error === null) {
setLoadedAudio(audio);
}
if (error) {
setIsPlaying(false);
Alert.alert(
'Error: The sound could not be played',
`Something went wrong during the sound playback. The sound playback is a new feature, and it might have problems. Could you please try to play the sound one more time?`
);
}
}
);

setIsPlaying(true);
}, [text, language, setIsPlaying, setLoadedAudio, loadedAudio]);

useEffect(() => {
if (isPlaying && loadedAudio) {
loadedAudio.play(() => {
setIsPlaying(false);
});
}
}, [isPlaying, loadedAudio, setIsPlaying]);

return (
<Pressable
disabled={isPlaying}
style={({ pressed }) => [
{
opacity: pressed ? 0.25 : 0.5,
},
style,
]}
onPress={playSound}
>
<Icon
name={isPlaying ? 'volume-medium' : 'play-circle'}
style={{
color: theme.colors.onBackground,
}}
size={size}
/>
</Pressable>
);
};
47 changes: 33 additions & 14 deletions mobile-app/src/study/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { CardItem } from '@vocably/model';
import React, { FC, useRef } from 'react';
import { CardItem, GoogleLanguage } from '@vocably/model';
import React, { FC, useCallback, useRef, useState } from 'react';
import {
Animated,
StyleSheet,
TouchableWithoutFeedback,
View,
} from 'react-native';
import { Text, useTheme } from 'react-native-paper';
import { PlaySound } from '../PlaySound';
import { SideB } from '../SideB';
import { Displayer } from './Displayer';

Expand Down Expand Up @@ -60,37 +61,62 @@ export const Card: FC<{ card: CardItem }> = ({ card }) => {
],
};

const flipToFront = () => {
const [isFlipped, setIsFlipped] = useState(false);

const flipToFront = useCallback(() => {
setIsFlipped(false);
Animated.timing(flipAnimation, {
toValue: 180,
duration: 300,
useNativeDriver: true,
}).start();
};
const flipToBack = () => {
}, [Animated, flipAnimation, setIsFlipped]);

const flipToBack = useCallback(() => {
setIsFlipped(true);
Animated.timing(flipAnimation, {
toValue: 0,
duration: 300,
useNativeDriver: true,
}).start();
};
}, [Animated, flipAnimation, setIsFlipped]);

const theme = useTheme();

return (
<Displayer>
<TouchableWithoutFeedback
onPress={() => (!!flipRotation ? flipToBack() : flipToFront())}
style={{ borderStyle: 'solid', borderColor: '#f00', borderWidth: 1 }}
>
<View style={styles.container}>
<Animated.View
style={{
...styles.cardBack,
...flipToFrontStyle,
display: 'flex',
}}
>
<SideB
card={card.data}
style={styles.list}
textStyle={{ fontSize: 24 }}
/>
</Animated.View>
<Animated.View style={{ ...styles.cardFront, ...flipToBackStyle }}>
<View
style={{
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'center',
alignItems: 'baseline',
}}
>
<PlaySound
text={card.data.source}
language={card.data.language as GoogleLanguage}
size={24}
style={{ marginRight: 6 }}
/>
<Text style={{ fontSize: 32, color: theme.colors.secondary }}>
{card.data.source}
</Text>
Expand All @@ -99,13 +125,6 @@ export const Card: FC<{ card: CardItem }> = ({ card }) => {
)}
</View>
</Animated.View>
<Animated.View style={{ ...styles.cardBack, ...flipToFrontStyle }}>
<SideB
card={card.data}
style={styles.list}
textStyle={{ fontSize: 24 }}
/>
</Animated.View>
</View>
</TouchableWithoutFeedback>
</Displayer>
Expand Down

0 comments on commit 2fbf97e

Please sign in to comment.