Skip to content

Commit f852534

Browse files
committed
refactor: extract audio play logic to a hook
1 parent e7b97d9 commit f852534

File tree

3 files changed

+76
-87
lines changed

3 files changed

+76
-87
lines changed

package/src/components/Attachment/AudioAttachment.tsx

Lines changed: 25 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import type { FileUpload } from '../../types/types';
1818
import { getTrimmedAttachmentTitle } from '../../utils/getTrimmedAttachmentTitle';
1919
import { ProgressControl } from '../ProgressControl/ProgressControl';
2020
import { WaveProgressBar } from '../ProgressControl/WaveProgressBar';
21+
import { useAudioPlayer } from '../../hooks/useAudioPlayer';
2122

2223
dayjs.extend(duration);
2324

@@ -50,14 +51,13 @@ export const AudioAttachment = (props: AudioAttachmentProps) => {
5051
showSpeedSettings = false,
5152
testID,
5253
} = props;
53-
54-
const handleLoadStart = () => {
55-
// For native CLI
56-
if (soundRef.current?.pause) soundRef.current.pause();
57-
};
54+
const { changeAudioSpeed, playAudio, pauseAudio, seekAudio } = useAudioPlayer({ soundRef });
55+
const isExpoCLI = !Sound.Player && Sound.initializeSound;
5856

5957
/** This is for Native CLI Apps */
6058
const handleLoad = (payload: VideoPayloadData) => {
59+
if (isExpoCLI) return;
60+
pauseAudio();
6161
onLoad(item.id, item.duration || payload.duration);
6262
};
6363

@@ -71,18 +71,6 @@ export const AudioAttachment = (props: AudioAttachmentProps) => {
7171
}
7272
};
7373

74-
/** This is for Native CLI Apps */
75-
const handleEnd = async () => {
76-
setAudioFinished(false);
77-
if (soundRef.current) {
78-
// For native CLI
79-
if (soundRef.current.seek) soundRef.current.seek(0);
80-
if (soundRef.current.pause) soundRef.current.pause();
81-
// For expo CLI
82-
if (soundRef.current.setPositionAsync) await soundRef.current.setPositionAsync(0);
83-
}
84-
};
85-
8674
const onPlaybackStateChanged = (playbackState: PlaybackStatus) => {
8775
if (playbackState.isPlaying === false) {
8876
onPlayPause(item.id, true);
@@ -96,46 +84,28 @@ export const AudioAttachment = (props: AudioAttachmentProps) => {
9684
onProgress(item.id, seekResponse.currentTime);
9785
};
9886

99-
const handlePlayPause = async (isPausedStatusAvailable?: boolean) => {
100-
if (!soundRef.current) return;
101-
if (isPausedStatusAvailable === undefined) {
102-
if (item.paused) {
103-
// For native CLI
104-
if (soundRef.current.resume) soundRef.current.resume();
105-
// For expo CLI
106-
if (soundRef.current.playAsync) await soundRef.current.playAsync();
107-
if (soundRef.current.setProgressUpdateIntervalAsync)
108-
await soundRef.current.setProgressUpdateIntervalAsync(60);
109-
} else {
110-
// For native CLI
111-
if (soundRef.current.pause) soundRef.current.pause();
112-
// For expo CLI
113-
if (soundRef.current.pauseAsync) await soundRef.current.pauseAsync();
114-
}
87+
const handlePlayPause = async () => {
88+
if (item.paused) {
89+
await playAudio();
11590
} else {
116-
onPlayPause(item.id, isPausedStatusAvailable);
91+
await pauseAudio();
11792
}
11893
};
11994

120-
const dragStart = async () => {
121-
// For native CLI
122-
if (soundRef.current?.pause) soundRef.current.pause();
95+
/** This is for Native CLI Apps */
96+
const handleEnd = async () => {
97+
setAudioFinished(false);
98+
await seekAudio(0);
99+
await pauseAudio();
100+
};
123101

124-
// For expo CLI
125-
if (soundRef.current?.pauseAsync) await soundRef.current.pauseAsync();
102+
const dragStart = async () => {
103+
await pauseAudio();
126104
};
127105

128106
const dragEnd = async (currentTime: number) => {
129-
// For native CLI
130-
if (soundRef.current?.seek) soundRef.current.seek(currentTime);
131-
// For expo CLI
132-
if (soundRef.current?.setPositionAsync) {
133-
await soundRef.current.setPositionAsync(currentTime * 1000);
134-
}
135-
// For native CLI
136-
if (soundRef.current?.resume) soundRef.current.resume();
137-
// For expo CLI
138-
if (soundRef.current?.playAsync) await soundRef.current.playAsync();
107+
await seekAudio(currentTime);
108+
await playAudio();
139109
};
140110

141111
/** For Expo CLI */
@@ -154,10 +124,8 @@ export const AudioAttachment = (props: AudioAttachmentProps) => {
154124
// Update your UI for the loaded state
155125
if (playbackStatus.isPlaying) {
156126
onPlayPause(item.id, false);
157-
// Update your UI for the playing state
158127
onProgress(item.id, positionMillis / 1000);
159128
} else {
160-
// Update your UI for the paused state
161129
onPlayPause(item.id, true);
162130
}
163131

@@ -173,8 +141,9 @@ export const AudioAttachment = (props: AudioAttachmentProps) => {
173141
}
174142
};
175143

144+
// This is for Expo CLI, sound initialization is done here.
176145
useEffect(() => {
177-
if (Sound.Player === null) {
146+
if (isExpoCLI) {
178147
const initiateSound = async () => {
179148
if (item && item.file && item.file.uri) {
180149
soundRef.current = await Sound.initializeSound(
@@ -196,45 +165,17 @@ export const AudioAttachment = (props: AudioAttachmentProps) => {
196165
// eslint-disable-next-line react-hooks/exhaustive-deps
197166
}, []);
198167

199-
// This is needed for expo applications where the rerender doesn't occur on time thefore you need to update the state of the sound.
200-
useEffect(() => {
201-
const initalPlayPause = async () => {
202-
if (soundRef.current) {
203-
if (item.paused) {
204-
if (soundRef.current.pauseAsync) await soundRef.current.pauseAsync();
205-
} else {
206-
if (soundRef.current.playAsync) await soundRef.current.playAsync();
207-
if (soundRef.current.setProgressUpdateIntervalAsync)
208-
await soundRef.current.setProgressUpdateIntervalAsync(60);
209-
}
210-
}
211-
};
212-
// For expo CLI
213-
if (!Sound.Player) {
214-
initalPlayPause();
215-
}
216-
}, [item.paused]);
217-
218168
const onSpeedChangeHandler = async () => {
219169
if (currentSpeed === 2.0) {
220170
setCurrentSpeed(1.0);
221-
// For expo CLI
222-
if (soundRef.current && soundRef.current.setRateAsync) {
223-
await soundRef.current.setRateAsync(1.0);
224-
}
171+
await changeAudioSpeed(1.0);
225172
} else {
226173
if (currentSpeed === 1.0) {
227174
setCurrentSpeed(1.5);
228-
// For expo CLI
229-
if (soundRef.current && soundRef.current.setRateAsync) {
230-
await soundRef.current.setRateAsync(1.5);
231-
}
175+
await changeAudioSpeed(1.5);
232176
} else if (currentSpeed === 1.5) {
233177
setCurrentSpeed(2.0);
234-
// For expo CLI
235-
if (soundRef.current && soundRef.current.setRateAsync) {
236-
await soundRef.current.setRateAsync(2.0);
237-
}
178+
await changeAudioSpeed(2.0);
238179
}
239180
}
240181
};
@@ -288,7 +229,7 @@ export const AudioAttachment = (props: AudioAttachmentProps) => {
288229
>
289230
<Pressable
290231
accessibilityLabel='Play Pause Button'
291-
onPress={() => handlePlayPause()}
232+
onPress={handlePlayPause}
292233
style={[
293234
styles.playPauseButton,
294235
{ backgroundColor: static_white, shadowColor: black },
@@ -327,7 +268,6 @@ export const AudioAttachment = (props: AudioAttachmentProps) => {
327268
<Sound.Player
328269
onEnd={handleEnd}
329270
onLoad={handleLoad}
330-
onLoadStart={handleLoadStart}
331271
onPlaybackStateChanged={onPlaybackStateChanged}
332272
onProgress={handleProgress}
333273
onSeek={onSeek}

package/src/components/Attachment/FileAttachmentGroup.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,13 @@ const FileAttachmentGroupWithContext = <
140140
onPlayPause={onPlayPause}
141141
onProgress={onProgress}
142142
showSpeedSettings={true}
143-
testID='audio-attachment-preview'
144143
/>
145144
) : (
146145
<Attachment attachment={file} />
147146
)
148-
) : null}
147+
) : (
148+
<Attachment attachment={file} />
149+
)}
149150
</View>
150151
))}
151152
</View>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { Sound, SoundReturnType } from '../native';
2+
3+
export type UseSoundPlayerProps = {
4+
soundRef: React.MutableRefObject<SoundReturnType | null>;
5+
};
6+
7+
/**
8+
* This hook is used to play, pause, seek and change audio speed.
9+
* It handles both Expo CLI and Native CLI.
10+
*/
11+
export const useAudioPlayer = (props: UseSoundPlayerProps) => {
12+
const { soundRef } = props;
13+
14+
const isExpoCLI = !Sound.Player && Sound.initializeSound;
15+
16+
const playAudio = async () => {
17+
if (isExpoCLI) {
18+
if (soundRef.current?.playAsync) await soundRef.current.playAsync();
19+
} else {
20+
if (soundRef.current?.resume) soundRef.current.resume();
21+
}
22+
};
23+
24+
const pauseAudio = async () => {
25+
if (isExpoCLI) {
26+
if (soundRef.current?.pauseAsync) await soundRef.current.pauseAsync();
27+
} else {
28+
if (soundRef.current?.pause) soundRef.current.pause();
29+
}
30+
};
31+
32+
const seekAudio = async (currentTime: number) => {
33+
if (isExpoCLI) {
34+
if (soundRef.current?.setPositionAsync)
35+
await soundRef.current.setPositionAsync(currentTime * 1000);
36+
} else {
37+
if (soundRef.current?.seek) soundRef.current.seek(currentTime);
38+
}
39+
};
40+
41+
const changeAudioSpeed = async (speed: number) => {
42+
// Handled through prop `rate` in `Sound.Player`
43+
if (!isExpoCLI) return;
44+
if (soundRef.current?.setRateAsync) await soundRef.current.setRateAsync(speed);
45+
};
46+
47+
return { playAudio, pauseAudio, seekAudio, changeAudioSpeed };
48+
};

0 commit comments

Comments
 (0)