Skip to content

Commit 9bff4cd

Browse files
Merge pull request #122 from dprevost-LMI/show-recoring-on-boot-and-delete-recording
feat: [Example App] keep recording on reboot + allow to delete them
2 parents 05d9dbc + c164249 commit 9bff4cd

File tree

5 files changed

+91
-6
lines changed

5 files changed

+91
-6
lines changed

example/src/App.tsx

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import React, {
1818
} from 'react';
1919
import {
2020
ActivityIndicator,
21+
Alert,
2122
Image,
2223
Linking,
2324
Pressable,
@@ -35,11 +36,13 @@ import { Icons } from './assets';
3536
import {
3637
generateAudioList,
3738
playbackSpeedSequence,
39+
getRecordedAudios,
3840
type ListItem,
3941
} from './constants';
4042
import stylesheet from './styles';
4143
import { Colors } from './theme';
4244
import FastImage from 'react-native-fast-image';
45+
import fs from 'react-native-fs';
4346

4447
const RenderListItem = React.memo(
4548
({
@@ -224,6 +227,7 @@ const AppContainer = () => {
224227
const [shouldScroll, setShouldScroll] = useState<boolean>(true);
225228
const [currentPlaying, setCurrentPlaying] = useState<string>('');
226229
const [list, setList] = useState<ListItem[]>([]);
230+
const [nbOfRecording, setNumberOfRecording] = useState<number>(0);
227231
const [currentPlaybackSpeed, setCurrentPlaybackSpeed] =
228232
useState<PlaybackSpeedType>(1.0);
229233

@@ -238,6 +242,12 @@ const AppContainer = () => {
238242
});
239243
}, []);
240244

245+
useEffect(() => {
246+
getRecordedAudios().then(recordedAudios =>
247+
setNumberOfRecording(recordedAudios.length)
248+
);
249+
}, [list]);
250+
241251
const changeSpeed = () => {
242252
setCurrentPlaybackSpeed(
243253
prev =>
@@ -248,6 +258,35 @@ const AppContainer = () => {
248258
);
249259
};
250260

261+
const handleDeleteRecordings = async () => {
262+
const recordings = await getRecordedAudios();
263+
264+
const deleteRecordings = async () => {
265+
await Promise.all(recordings.map(async recording => fs.unlink(recording)))
266+
.then(() => {
267+
generateAudioList().then(audioListArray => {
268+
setList(audioListArray);
269+
});
270+
})
271+
.catch(error => {
272+
Alert.alert(
273+
'Error deleting recordings',
274+
'Below error happened while deleting recordings:\n' + error,
275+
[{ text: 'Dismiss' }]
276+
);
277+
});
278+
};
279+
280+
Alert.alert(
281+
'Delete all recording',
282+
`Continue to delete all ${recordings.length} recordings.`,
283+
[
284+
{ text: 'Cancel', style: 'cancel' },
285+
{ text: 'OK', onPress: deleteRecordings },
286+
]
287+
);
288+
};
289+
251290
return (
252291
<View style={styles.appContainer}>
253292
<StatusBar
@@ -259,12 +298,28 @@ const AppContainer = () => {
259298
<GestureHandlerRootView style={styles.appContainer}>
260299
<View style={styles.screenBackground}>
261300
<View style={styles.container}>
262-
<View style={styles.simformImageContainer}>
301+
<View style={styles.headerContainer}>
263302
<Image
264303
source={Icons.simform}
265304
style={styles.simformImage}
266305
resizeMode="contain"
267306
/>
307+
<Pressable
308+
style={[
309+
styles.deleteRecordingContainer,
310+
{ opacity: nbOfRecording ? 1 : 0.5 },
311+
]}
312+
onPress={handleDeleteRecordings}
313+
disabled={!nbOfRecording}>
314+
<Image
315+
source={Icons.delete}
316+
style={styles.pinkButtonImage}
317+
resizeMode="contain"
318+
/>
319+
<Text style={styles.deleteRecordingTitle}>
320+
{'Delete recorded audio files'}
321+
</Text>
322+
</Pressable>
268323
</View>
269324
<ScrollView scrollEnabled={shouldScroll}>
270325
{list.map(item => (
7.72 KB
Loading

example/src/assets/icons/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export const Icons = {
44
simform: require('./simform.png'),
55
mic: require('./mic.png'),
66
logo: require('./logo.png'),
7+
delete: require('./delete.png'),
78
};

example/src/constants/Audios.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import fs from 'react-native-fs';
22
import RNFetchBlob from 'rn-fetch-blob';
33
import { globalMetrics } from '../../src/theme';
4+
import { Platform } from 'react-native';
45

56
export interface ListItem {
67
fromCurrentUser: boolean;
@@ -69,17 +70,30 @@ const audioAssetArray = [
6970
'file_example_mp3_15s.mp3',
7071
];
7172

73+
/**
74+
* Retrieve previously recorded audio files from the cache/document directory.
75+
* @returns
76+
*/
77+
export const getRecordedAudios = async (): Promise<string[]> => {
78+
const recordingSavingPath = Platform.select({ ios: fs.DocumentDirectoryPath, default: fs.CachesDirectoryPath })
79+
80+
const items = await fs.readDir(recordingSavingPath)
81+
return items.filter(item => item.path.endsWith('.m4a')).map(item => item.path)
82+
}
83+
7284
/**
7385
* Generate a list of file objects with information about successfully copied files (Android)
7486
* or all files (iOS).
7587
* @returns {Promise<ListItem[]>} A Promise that resolves to the list of file objects.
7688
*/
7789
export const generateAudioList = async (): Promise<ListItem[]> => {
78-
const audioAssets = await copyFilesToNativeResources();
90+
const audioAssetPaths = (await copyFilesToNativeResources()).map(value => `${filePath}/${value}`);
91+
const recordedAudios = await getRecordedAudios()
7992

8093
// Generate the final list based on the copied or available files
81-
return audioAssets?.map?.((value, index) => ({
94+
return [...audioAssetPaths, ...recordedAudios].map?.((value, index) => ({
8295
fromCurrentUser: index % 2 !== 0,
83-
path: `${filePath}/${value}`,
96+
path: value,
8497
}));
98+
8599
};

example/src/styles.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ const styles = (params: StyleSheetParams = {}) =>
5454
tintColor: Colors.white,
5555
alignSelf: 'flex-end',
5656
},
57+
pinkButtonImage: {
58+
height: scale(22),
59+
width: scale(22),
60+
tintColor: Colors.pink,
61+
alignSelf: 'flex-end',
62+
},
5763
staticWaveformView: {
5864
flex: 1,
5965
height: scale(75),
@@ -90,9 +96,18 @@ const styles = (params: StyleSheetParams = {}) =>
9096
width: '100%',
9197
tintColor: Colors.pink,
9298
},
93-
simformImageContainer: {
99+
headerContainer: {
94100
alignItems: 'center',
95-
justifyContent: 'center',
101+
},
102+
deleteRecordingContainer: {
103+
alignItems: 'center',
104+
flexDirection: 'row',
105+
},
106+
deleteRecordingTitle: {
107+
fontSize: scale(20),
108+
fontWeight: 'bold',
109+
color: Colors.pink,
110+
paddingLeft: scale(8),
96111
},
97112
loadingText: {
98113
color: Colors.black,

0 commit comments

Comments
 (0)