Skip to content

Commit 8bcd96b

Browse files
committed
feat: create useAudioPreviewManager
1 parent 97a0491 commit 8bcd96b

File tree

2 files changed

+106
-79
lines changed

2 files changed

+106
-79
lines changed

package/src/components/MessageInput/AttachmentUploadPreviewList.tsx

Lines changed: 8 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
22
import { FlatList, LayoutChangeEvent, StyleSheet, View } from 'react-native';
33

44
import {
5-
isAudioAttachment,
65
isLocalAudioAttachment,
76
isLocalFileAttachment,
87
isLocalImageAttachment,
98
isLocalVoiceRecordingAttachment,
109
isVideoAttachment,
11-
isVoiceRecordingAttachment,
1210
LocalAttachment,
1311
LocalImageAttachment,
1412
} from 'stream-chat';
1513

14+
import { useAudioPreviewManager } from './hooks/useAudioPreviewManager';
15+
1616
import { useMessageComposer } from '../../contexts';
1717
import { useAttachmentManagerState } from '../../contexts/messageInputContext/hooks/useAttachmentManagerState';
1818
import {
@@ -21,7 +21,6 @@ import {
2121
} from '../../contexts/messageInputContext/MessageInputContext';
2222
import { useTheme } from '../../contexts/themeContext/ThemeContext';
2323
import { isSoundPackageAvailable } from '../../native';
24-
import { AudioConfig } from '../../types/types';
2524

2625
const IMAGE_PREVIEW_SIZE = 100;
2726
const FILE_PREVIEW_HEIGHT = 60;
@@ -42,9 +41,6 @@ const UnMemoizedAttachmentUploadListPreview = (
4241
props: AttachmentUploadPreviewListPropsWithContext,
4342
) => {
4443
const [flatListWidth, setFlatListWidth] = useState(0);
45-
const [audioAttachmentsStateMap, setAudioAttachmentsStateMap] = useState<
46-
Record<string, AudioConfig>
47-
>({});
4844
const flatListRef = useRef<FlatList<LocalAttachment> | null>(null);
4945
const {
5046
AudioAttachmentUploadPreview,
@@ -68,82 +64,15 @@ const UnMemoizedAttachmentUploadListPreview = (
6864
const fileUploads = useMemo(() => {
6965
return attachments.filter((attachment) => !isLocalImageAttachment(attachment));
7066
}, [attachments]);
71-
72-
useEffect(() => {
73-
const newAudioAttachmentsStateMap = fileUploads.reduce(
74-
(acc, attachment) => {
75-
if (isAudioAttachment(attachment) || isVoiceRecordingAttachment(attachment)) {
76-
acc[attachment.localMetadata.id] = {
77-
duration:
78-
attachment.duration ||
79-
audioAttachmentsStateMap[attachment.localMetadata.id]?.duration ||
80-
0,
81-
paused: true,
82-
progress: 0,
83-
};
84-
}
85-
return acc;
86-
},
87-
{} as Record<string, AudioConfig>,
67+
const audioUploads = useMemo(() => {
68+
return fileUploads.filter(
69+
(attachment) =>
70+
isLocalAudioAttachment(attachment) || isLocalVoiceRecordingAttachment(attachment),
8871
);
89-
90-
setAudioAttachmentsStateMap(newAudioAttachmentsStateMap);
91-
// eslint-disable-next-line react-hooks/exhaustive-deps
9272
}, [fileUploads]);
9373

94-
// Handler triggered when an audio is loaded in the message input. The initial state is defined for the audio here
95-
// and the duration is set.
96-
const onLoad = useCallback((index: string, duration: number) => {
97-
setAudioAttachmentsStateMap((prevState) => ({
98-
...prevState,
99-
[index]: {
100-
...prevState[index],
101-
duration,
102-
},
103-
}));
104-
}, []);
105-
106-
// The handler which is triggered when the audio progresses/ the thumb is dragged in the progress control. The
107-
// progressed duration is set here.
108-
const onProgress = useCallback((index: string, progress: number) => {
109-
setAudioAttachmentsStateMap((prevState) => ({
110-
...prevState,
111-
[index]: {
112-
...prevState[index],
113-
progress,
114-
},
115-
}));
116-
}, []);
117-
118-
// The handler which controls or sets the paused/played state of the audio.
119-
const onPlayPause = useCallback((index: string, pausedStatus?: boolean) => {
120-
if (pausedStatus === false) {
121-
// In this case, all others except the index are set to paused.
122-
setAudioAttachmentsStateMap((prevState) => {
123-
const newState = { ...prevState };
124-
Object.keys(newState).forEach((key) => {
125-
if (key !== index) {
126-
newState[key].paused = true;
127-
}
128-
});
129-
return {
130-
...newState,
131-
[index]: {
132-
...newState[index],
133-
paused: false,
134-
},
135-
};
136-
});
137-
} else {
138-
setAudioAttachmentsStateMap((prevState) => ({
139-
...prevState,
140-
[index]: {
141-
...prevState[index],
142-
paused: true,
143-
},
144-
}));
145-
}
146-
}, []);
74+
const { audioAttachmentsStateMap, onLoad, onProgress, onPlayPause } =
75+
useAudioPreviewManager(audioUploads);
14776

14877
const renderImageItem = useCallback(
14978
({ item }: { item: LocalImageAttachment }) => {
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { useCallback, useEffect, useState } from 'react';
2+
3+
import { LocalAttachment } from 'stream-chat';
4+
5+
import { AudioConfig } from '../../../types/types';
6+
7+
/**
8+
* Manages the state of audio attachments for preview and playback.
9+
* @param files The audio files to manage.
10+
* @returns An object containing the state and handlers for audio attachments.
11+
*/
12+
export const useAudioPreviewManager = (files: LocalAttachment[]) => {
13+
const [audioAttachmentsStateMap, setAudioAttachmentsStateMap] = useState<
14+
Record<string, AudioConfig>
15+
>({});
16+
17+
useEffect(() => {
18+
const updatedStateMap = Object.fromEntries(
19+
files.map((attachment) => {
20+
const id = attachment.localMetadata.id;
21+
const existingConfig = audioAttachmentsStateMap[id];
22+
23+
const config: AudioConfig = {
24+
duration: attachment.duration ?? existingConfig?.duration ?? 0,
25+
paused: true,
26+
progress: 0,
27+
};
28+
29+
return [id, config];
30+
}),
31+
);
32+
33+
setAudioAttachmentsStateMap(updatedStateMap);
34+
// eslint-disable-next-line react-hooks/exhaustive-deps
35+
}, [files]);
36+
37+
// Handler triggered when an audio is loaded in the message input. The initial state is defined for the audio here
38+
// and the duration is set.
39+
const onLoad = useCallback((index: string, duration: number) => {
40+
setAudioAttachmentsStateMap((prevState) => ({
41+
...prevState,
42+
[index]: {
43+
...prevState[index],
44+
duration,
45+
},
46+
}));
47+
}, []);
48+
49+
// The handler which is triggered when the audio progresses/ the thumb is dragged in the progress control. The
50+
// progressed duration is set here.
51+
const onProgress = useCallback((index: string, progress: number) => {
52+
setAudioAttachmentsStateMap((prevState) => ({
53+
...prevState,
54+
[index]: {
55+
...prevState[index],
56+
progress,
57+
},
58+
}));
59+
}, []);
60+
61+
// The handler which controls or sets the paused/played state of the audio.
62+
const onPlayPause = useCallback((index: string, pausedStatus?: boolean) => {
63+
if (pausedStatus === false) {
64+
// In this case, all others except the index are set to paused.
65+
setAudioAttachmentsStateMap((prevState) => {
66+
const newState = { ...prevState };
67+
Object.keys(newState).forEach((key) => {
68+
if (key !== index) {
69+
newState[key].paused = true;
70+
}
71+
});
72+
return {
73+
...newState,
74+
[index]: {
75+
...newState[index],
76+
paused: false,
77+
},
78+
};
79+
});
80+
} else {
81+
setAudioAttachmentsStateMap((prevState) => ({
82+
...prevState,
83+
[index]: {
84+
...prevState[index],
85+
paused: true,
86+
},
87+
}));
88+
}
89+
}, []);
90+
91+
return {
92+
audioAttachmentsStateMap,
93+
onLoad,
94+
onPlayPause,
95+
onProgress,
96+
setAudioAttachmentsStateMap,
97+
};
98+
};

0 commit comments

Comments
 (0)