Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4130e41
Add props for global option of voice recoring
HoonBaek Feb 2, 2023
a12c5d8
Create VoiceMessageInputWrapper component
HoonBaek Feb 2, 2023
33da86b
Modify the VoiceMessageInput clear state logic
HoonBaek Feb 2, 2023
13dc596
Add props for voice message to the MessageInput component
HoonBaek Feb 2, 2023
f157bb3
Modify the playback time calculation logic
HoonBaek Feb 2, 2023
cd5d38a
Send voice message on Channel
HoonBaek Feb 2, 2023
04ff001
Create useSendVoiceMessageCallback hook in Channel
HoonBaek Feb 2, 2023
52ed1c2
Put VoiceRecorderProvider and VoicePlayerProvider into SendbirdProvider
HoonBaek Feb 2, 2023
6f73f03
Add type definitions for voice message
HoonBaek Feb 2, 2023
9a2dc2d
Apply voice message to the MessageContent
HoonBaek Feb 2, 2023
8e30c93
Appear the border radius of VoiceMessageItemBody
HoonBaek Feb 2, 2023
dfcd878
Set file name, Voice message when recording voice
HoonBaek Feb 2, 2023
7f9d133
Apply audio duration to VoiceMessageInput and VoiceMessageItem
HoonBaek Feb 2, 2023
efcebd0
Rename file name VoiceMessageWrapper to VoiceMessageInputWrapper
HoonBaek Feb 2, 2023
67fdd20
Stop recording automatically when clicking send button
HoonBaek Feb 2, 2023
d0fafb9
Apply VoiceMessageInput and VoiceMessageItem to the Thread
HoonBaek Feb 2, 2023
746ab93
Activate ProgressBar in play mode of VoiceMessageInput
HoonBaek Feb 2, 2023
547349b
Modify the VoiceMessageInput ProgressBar progress frame
HoonBaek Feb 2, 2023
ceac501
Stop recording when out of maxRecordingTime
HoonBaek Feb 3, 2023
a7d5351
Change the voice message internal protocol
HoonBaek Feb 6, 2023
301717f
Add a file extension to the file name when sending voice message
HoonBaek Feb 7, 2023
51067e8
Add new icon AudioOnLined & Migrate Icon util functions to TS
HoonBaek Feb 7, 2023
412ff5d
Apply the audio icon into the MessageInput component
HoonBaek Feb 7, 2023
c876648
Modify PlaybackTime comp to round down with time
HoonBaek Feb 7, 2023
18242c7
Replace the AudioOnLined icon with same width and height size
HoonBaek Feb 7, 2023
c77d4f4
Add a storybook of PlaybackTime component
HoonBaek Feb 7, 2023
28c8414
Make playback time to count down when playing audio
HoonBaek Feb 7, 2023
cdd7f19
Remove unexpected use of file extension & Add missing return type
HoonBaek Feb 7, 2023
51ebf0a
Disable the send button by minRecordingTime of VoiceMessageInput
HoonBaek Feb 7, 2023
045f2b7
Apply minRecordingTime to the VoiceMessageInput behavior
HoonBaek Feb 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/hooks/useVoiceRecorder/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const VoiceRecorderProvider = (props: VoiceRecorderProps): React.ReactEle
const mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = (e) => {// when recording stops
// Generate audio file
const audioFile = new File([e.data], 'I am file name', {
const audioFile = new File([e.data], 'Voice message', {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Voice message need extension, no?

lastModified: new Date().getTime(),
type: 'audio/mpeg',
});
Expand Down
16 changes: 16 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ interface SendBirdProviderProps {
resizingHeight?: number | string,
};
isMentionEnabled?: boolean;
isVoiceMessageEnabled?: boolean;
voiceRecord?: {
maxRecordingTime?: number,
minRecordingTime?: number,
};
// isTypingIndicatorEnabledOnChannelList?: boolean;
// isMessageReceiptStatusEnabledOnChannelList?: boolean;
}
Expand Down Expand Up @@ -145,6 +150,11 @@ interface SendBirdStateConfig {
resizingWidth?: number | string,
resizingHeight?: number | string,
};
isVoiceMessageEnabled?: boolean;
voiceRecord?: {
maxRecordingTime?: number,
minRecordingTime?: number,
};
isTypingIndicatorEnabledOnChannelList?: boolean;
isMessageReceiptStatusEnabledOnChannelList?: boolean;
}
Expand Down Expand Up @@ -281,6 +291,11 @@ interface AppProps {
config?: SendBirdProviderConfig;
isReactionEnabled?: boolean;
isMessageGroupingEnabled?: boolean;
isVoiceMessageEnabled?: boolean;
voiceRecord?: {
maxRecordingTime?: number,
minRecordingTime?: number,
};
stringSet?: Record<string, string>;
colorSet?: Record<string, string>;
imageCompression?: {
Expand Down Expand Up @@ -634,6 +649,7 @@ type ChannelContextProps = {
onBeforeSendFileMessage?(file: File, quotedMessage?: UserMessage | FileMessage): FileMessageCreateParams;
onBeforeUpdateUserMessage?(text: string): UserMessageUpdateParams;
onChatHeaderActionClick?(event: React.MouseEvent<HTMLElement>): void;
onBeforeSendVoiceMessage?: (file: File, quotedMessage?: UserMessage | FileMessage) => FileMessageCreateParams;
onSearchClick?(): void;
replyType?: ReplyType;
queries?: ChannelQueries;
Expand Down
22 changes: 21 additions & 1 deletion src/lib/Sendbird.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { LoggerFactory } from './Logger';
import pubSubFactory from './pubSub/index';
import useAppendDomNode from '../hooks/useAppendDomNode';

import { VoiceRecorderProvider } from '../hooks/useVoiceRecorder';
import { VoicePlayerProvider } from '../hooks/useVoicePlayer';
import { LocalizationProvider } from './LocalizationContext';
import { MediaQueryProvider } from './MediaQueryContext';
import getStringSet from '../ui/Label/stringSet';
Expand Down Expand Up @@ -50,6 +52,8 @@ export default function Sendbird(props) {
imageCompression,
isReactionEnabled,
isMentionEnabled,
isVoiceMessageEnabled,
voiceRecord,
isTypingIndicatorEnabledOnChannelList,
isMessageReceiptStatusEnabledOnChannelList,
replyType,
Expand Down Expand Up @@ -200,6 +204,8 @@ export default function Sendbird(props) {
},
isReactionEnabled,
isMentionEnabled: isMentionEnabled || false,
isVoiceMessageEnabled,
voiceRecord,
userMention: {
maxMentionCount: userMention?.maxMentionCount || 10,
maxSuggestionCount: userMention?.maxSuggestionCount || 15,
Expand All @@ -212,7 +218,11 @@ export default function Sendbird(props) {
>
<MediaQueryProvider logger={logger} mediaQueryBreakPoint={mediaQueryBreakPoint}>
<LocalizationProvider stringSet={localeStringSet} dateLocale={dateLocale}>
{children}
<VoiceRecorderProvider>
<VoicePlayerProvider>
{children}
</VoicePlayerProvider>
</VoiceRecorderProvider>
</LocalizationProvider>
</MediaQueryProvider>
</SendbirdSdkContext.Provider>
Expand Down Expand Up @@ -262,6 +272,11 @@ Sendbird.propTypes = {
colorSet: PropTypes.objectOf(PropTypes.string),
isReactionEnabled: PropTypes.bool,
isMentionEnabled: PropTypes.bool,
isVoiceMessageEnabled: PropTypes.bool,
voiceRecord: PropTypes.shape({
maxRecordingTime: PropTypes.number,
minRecordingTime: PropTypes.number,
}),
Comment on lines +275 to +279
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

discuss: isnt it better for this prop to be in Channel?

imageCompression: PropTypes.shape({
compressionRate: PropTypes.number,
resizingWidth: PropTypes.oneOfType([
Expand Down Expand Up @@ -300,6 +315,11 @@ Sendbird.defaultProps = {
imageCompression: {},
isReactionEnabled: true,
isMentionEnabled: false,
isVoiceMessageEnabled: true,
voiceRecord: {
maxRecordingTime: 60000,
minRecordingTime: 1000,
},
isTypingIndicatorEnabledOnChannelList: false,
isMessageReceiptStatusEnabledOnChannelList: false,
replyType: 'NONE',
Expand Down
10 changes: 10 additions & 0 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ export interface SendBirdProviderProps {
stringSet?: Record<string, string>;
colorSet?: Record<string, string>;
isMentionEnabled?: boolean;
isVoiceMessageEnabled?: boolean;
voiceRecord?: {
maxRecordingTime: number;
minRecordingTime: number;
};
imageCompression?: {
compressionRate?: number,
resizingWidth?: number | string,
Expand All @@ -68,6 +73,11 @@ export interface SendBirdStateConfig {
userListQuery?(): SendBirdTypes.UserListQuery;
isReactionEnabled: boolean;
isMentionEnabled: boolean;
isVoiceMessageEnabled?: boolean;
voiceRecord?: {
maxRecordingTime: number;
minRecordingTime: number;
};
userMention: {
maxMentionCount: number,
maxSuggestionCount: number,
Expand Down
14 changes: 14 additions & 0 deletions src/smart-components/App/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export default function App(props) {
config = {},
isReactionEnabled,
isMentionEnabled,
isVoiceMessageEnabled,
voiceRecord,
replyType,
isMessageGroupingEnabled,
colorSet,
Expand Down Expand Up @@ -66,6 +68,8 @@ export default function App(props) {
imageCompression={imageCompression}
isReactionEnabled={isReactionEnabled}
isMentionEnabled={isMentionEnabled}
isVoiceMessageEnabled={isVoiceMessageEnabled}
voiceRecord={voiceRecord}
onUserProfileMessage={(channel) => {
setCurrentChannel(channel);
}}
Expand Down Expand Up @@ -132,6 +136,11 @@ App.propTypes = {
}),
disableAutoSelect: PropTypes.bool,
isMentionEnabled: PropTypes.bool,
isVoiceMessageEnabled: PropTypes.bool,
voiceRecord: PropTypes.shape({
maxRecordingTime: PropTypes.number,
minRecordingTime: PropTypes.number,
}),
isTypingIndicatorEnabledOnChannelList: PropTypes.bool,
isMessageReceiptStatusEnabledOnChannelList: PropTypes.bool,
};
Expand All @@ -155,6 +164,11 @@ App.defaultProps = {
config: {},
isReactionEnabled: true,
isMentionEnabled: false,
isVoiceMessageEnabled: true,
voiceRecord: {
maxRecordingTime: 60000,
minRecordingTime: 1000,
},
replyType: 'NONE',
isMessageGroupingEnabled: true,
stringSet: null,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import React, { useEffect, useState } from 'react';
import './voice-message-wrapper.scss';

import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext';
import { useVoicePlayer } from '../../../../hooks/useVoicePlayer/useVoicePlayer';
import { useVoiceRecorder } from '../../../../hooks/useVoiceRecorder/useVoiceRecorder';
import VoiceMessageInput, { VoiceMessageInputStatus } from '../../../../ui/VoiceMessageInput';

export interface VoiceMessageInputWrapperProps {
onCancelClick?: () => void;
onSubmitClick?: (file: File, duration: number) => void;
}

export const VoiceMessageInputWrapper = ({
onCancelClick,
onSubmitClick,
}: VoiceMessageInputWrapperProps): React.ReactElement => {
const [currentAudioFile, setAudioFile] = useState(null);
const [audioDuration, setDuration] = useState(0);
const [voiceInputState, setVoiceInputState] = useState(VoiceMessageInputStatus.READY_TO_RECORD);
const [isRecording, setIsRecording] = useState(true);
const [isSubmited, setSubmit] = useState(false);
const { config } = useSendbirdStateContext();
const { voiceRecord } = config;
const { maxRecordingTime } = voiceRecord;
const {
start,
stop,
recordingTime,
} = useVoiceRecorder({
onRecordingStarted: () => {
setVoiceInputState(VoiceMessageInputStatus.RECORDING);
},
onRecordingEnded: (recordedFile) => {
setAudioFile(recordedFile);
setVoiceInputState(VoiceMessageInputStatus.READY_TO_PLAY);
},
});
const {
play,
pause,
} = useVoicePlayer({
onPlayingStarted: () => {
setVoiceInputState(VoiceMessageInputStatus.PLAYING);
},
onPlayingStopped: () => {
setVoiceInputState(VoiceMessageInputStatus.READY_TO_PLAY);
},
});

useEffect(() => {
if (voiceInputState === VoiceMessageInputStatus.READY_TO_RECORD
|| voiceInputState === VoiceMessageInputStatus.RECORDING
) {
setIsRecording(true);
} else {
setIsRecording(false);
}

if (voiceInputState === VoiceMessageInputStatus.READY_TO_PLAY) {
setDuration(recordingTime);
}
}, [voiceInputState]);
useEffect(() => {
if (isSubmited && currentAudioFile) {
onSubmitClick(currentAudioFile, recordingTime);
}
}, [isSubmited, currentAudioFile, recordingTime]);
useEffect(() => {
if (recordingTime >= maxRecordingTime) {
stop();
}
}, [recordingTime, maxRecordingTime]);

return (
<div className="sendbird-voice-message-input-wrapper">
<VoiceMessageInput
maxSize={isRecording ? maxRecordingTime : audioDuration}
inputState={voiceInputState}
onCancelClick={onCancelClick}
onSubmitClick={() => {
stop();
setSubmit(true);
}}
onRecordClick={() => {
start();
}}
onRecordStopClick={(playbackTime) => {
if (playbackTime >= 1000) {
stop();
} else {
setVoiceInputState(VoiceMessageInputStatus.READY_TO_RECORD);
}
}}
onPlayClick={() => {
play(currentAudioFile);
}}
onPauseClick={() => {
pause();
}}
/>
</div>
);
};

export default VoiceMessageInputWrapper;
Loading