Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
ad84356
Create ProgressBar component
HoonBaek Feb 1, 2023
899e3ca
Create UI component PlaybackTime
HoonBaek Feb 1, 2023
1742d72
Modify ProgressBar and update snapshot
HoonBaek Feb 1, 2023
463d882
Create UI comp VoiceMessageInput
HoonBaek Feb 1, 2023
59fb8c1
Create VoiceMessageItemBody component
HoonBaek Feb 2, 2023
e8b0392
Change the playback time unit to millisec
HoonBaek Feb 2, 2023
c208bb4
Add new icon color PRIMARY_2
HoonBaek Feb 2, 2023
a99e969
Accept labelColor in the PlaybackTime comp
HoonBaek Feb 2, 2023
5fd0d39
Apply color type to the ProgressBar comp
HoonBaek Feb 2, 2023
04a049a
Set progress bar height to 40px on the VoiceMessageInput comp
HoonBaek Feb 2, 2023
9a4845b
Use seconds unit in VoicePlayer
HoonBaek Feb 2, 2023
28385a0
Remove the empty storybook of PlayTime comp
HoonBaek Feb 2, 2023
249fb79
fix: Apply string set into the moderation section (#391)
HoonBaek Feb 1, 2023
e1090a4
fix: Use same word break and URL activation logic on messages (#392)
HoonBaek Feb 1, 2023
b605b6e
fix: Migrate the outdated ChannelListQuery interface (#393)
HoonBaek Feb 2, 2023
489a513
Set height of ProgressBar in the storybook sample
HoonBaek Feb 2, 2023
ff065dd
Put string value to enum definition
HoonBaek Feb 2, 2023
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
2758d05
Add string set for voice message input disabled status
HoonBaek Feb 8, 2023
1e342c8
Manage the voice message disabled state
HoonBaek Feb 8, 2023
be4d4e0
Provide context recordingLimit from VoiceRecorderProvider
HoonBaek Feb 8, 2023
53e3750
Migrate VoiceMessageInput comp to have only UI functions
HoonBaek Feb 12, 2023
4949948
Rename useVoiceRecorder hook to VoiceRecorder
HoonBaek Feb 12, 2023
30b7b9c
Rename useVoicePlayer hook to VoicePlayer
HoonBaek Feb 12, 2023
05e3696
Refactor VoiceRecorder and VoicePlayer to use globally
HoonBaek Feb 12, 2023
c41f885
Remove legacy files of VoicePlayer
HoonBaek Feb 12, 2023
cf30c7b
Check in and out using voice player in Channel and Thread
HoonBaek Feb 12, 2023
e232db9
Rename VoiceMessageInputControlTypes to VoiceMessageInputStatus
HoonBaek Feb 12, 2023
7953d04
Set the playbackTime to 0 when playing is finished
HoonBaek Feb 12, 2023
d432e3b
Modify VoiceMessageInput component using the refactored voice recorde…
HoonBaek Feb 12, 2023
bdb1501
Apply changed mimeType policy to the VoiceMessageItemBody component
HoonBaek Feb 13, 2023
8a2b5c6
Put voice message item into the ParentMessageInfoItem
HoonBaek Feb 14, 2023
1244c05
Change the on record flicker time to 1sec
HoonBaek Feb 14, 2023
7b04862
Modify the text overflow issue in the text message item
HoonBaek Feb 14, 2023
a682c4a
Fix the voice message width
HoonBaek Feb 14, 2023
36eebed
Apply OpenChannel to the storybook sample
HoonBaek Feb 14, 2023
f993e66
Apply minRecordTime to the VoiceMessageInput comp
HoonBaek Feb 14, 2023
af8f4d0
Fix: Make a recorded file playable in iOS by encoding to mp3
HoonBaek Feb 14, 2023
6629936
Install lamejs for encoding audio file to mp3 in local
HoonBaek Feb 14, 2023
983f91d
Chore: make the code prettier in WebAudioUtils file
HoonBaek Feb 14, 2023
ce50f03
Refactor logic of voice player to manage the player events
HoonBaek Feb 16, 2023
bc6605c
Remove legacy of previous voice player logic
HoonBaek Feb 16, 2023
52d09e0
Include metaArray when fetching message list
HoonBaek Feb 16, 2023
1b916ac
Fix: entire message list is re-rendered when one message property cha…
HoonBaek Feb 16, 2023
f0bf35e
Add string set 'Voice Message' and apply to ChannelList, QuoteMessage…
HoonBaek Feb 16, 2023
07cd116
Add interface to pause with groupKey of voice player
HoonBaek Feb 17, 2023
241a0b2
Reverse the on record flicker animation
HoonBaek Feb 17, 2023
23f3cfe
Remove the legacy logic check in/out channel in storybook sample
HoonBaek Feb 17, 2023
ed2aed0
Install lamejs for transcoding audio file to mp3
HoonBaek Feb 17, 2023
65d40b8
Merge branch 'develop/Voice-message' into fix/UIKIT-3053/Modify-issue…
HoonBaek Feb 17, 2023
c545c93
Use reply and thread in broadcast channel
HoonBaek Feb 20, 2023
fe2f7d3
Add option of voice message in the sample app
HoonBaek Feb 20, 2023
c9fb603
Modify sendbird RestrictionType error
HoonBaek Feb 20, 2023
662118f
feat: options to render icons on MessageInput (#406)
Feb 21, 2023
220a001
Export isVoiceMessage util function
HoonBaek Feb 21, 2023
eb388ae
Add type definitions for voice message & Export the modules
HoonBaek Feb 21, 2023
5edba64
Add new line to the end of file, voicePlayerEvent
HoonBaek Feb 21, 2023
bd32fd0
Convert a negative number to natural number in PlaybackTime comp
HoonBaek Feb 21, 2023
31ef428
Remove unnecessary lines and rename a variable
HoonBaek Feb 21, 2023
dcaf946
Modify the type of the return type of setInterval
HoonBaek Feb 21, 2023
e4f4a4e
Make variables to const within voice message feature
HoonBaek Feb 22, 2023
8aada4e
Rename const variables name to be capitalized
HoonBaek Feb 22, 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
11 changes: 11 additions & 0 deletions exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ export default {
useSendbirdStateContext: 'src/hooks/useSendbirdStateContext.tsx',
withSendbird: 'src/lib/SendbirdSdkContext.jsx',

// Voice message
'VoiceRecorder/context': 'src/hooks/VoiceRecorder/index.tsx',
'VoiceRecorder/useVoiceRecorder': 'src/hooks/VoiceRecorder/useVoiceRecorder.tsx',
'VoicePlayer/context': 'src/hooks/VoicePlayer/index.tsx',
'VoicePlayer/useVoicePlayer': 'src/hooks/VoicePlayer/useVoicePlayer.tsx',

// handlers - experimental
'handlers/ConnectionHandler': 'src/lib/handlers/ConnectionHandler.ts',
'handlers/GroupChannelHandler': 'src/lib/handlers/GroupChannelHandler.ts',
Expand All @@ -20,6 +26,7 @@ export default {

// utils
'utils/message/getOutgoingMessageState': 'src/utils/exports/getOutgoingMessageState.ts',
'utils/message/isVoiceMessage': 'src/utils/isVoiceMessage.ts',

// ChannelList
ChannelList: 'src/smart-components/ChannelList/index.tsx',
Expand Down Expand Up @@ -159,6 +166,8 @@ export default {
'ui/OpenchannelThumbnailMessage': 'src/ui/OpenchannelThumbnailMessage/index.tsx',
'ui/OpenchannelUserMessage': 'src/ui/OpenchannelUserMessage/index.tsx',
'ui/PlaceHolder': 'src/ui/PlaceHolder/index.tsx',
'ui/PlaybackTime': 'src/ui/PlaybackTime/index.tsx',
'ui/ProgressBar': 'src/ui/ProgressBar/index.tsx',
'ui/QuoteMessage': 'src/ui/QuoteMessage/index.tsx',
'ui/QuoteMessageInput': 'src/ui/QuoteMessageInput/index.tsx',
'ui/ReactionBadge': 'src/ui/ReactionBadge/index.tsx',
Expand All @@ -173,5 +182,7 @@ export default {
'ui/UnknownMessageItemBody': 'src/ui/UnknownMessageItemBody/index.tsx',
'ui/UserListItem': 'src/ui/UserListItem/index.tsx',
'ui/UserProfile': 'src/ui/UserProfile/index.tsx',
'ui/VoiceMessgeInput': 'src/ui/VoiceMessageInput/index.tsx',
'ui/VoiceMessageItemBody': 'src/ui/VoiceMessageItemBody.tsx',
'ui/Word': 'src/ui/Word/index.tsx',
};
27 changes: 27 additions & 0 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
"files": [
"release/**/*",
"dist/**/*",
"package-lock.json",
"LICENSE",
"CHANGELOG.md"
],
Expand Down Expand Up @@ -52,6 +51,7 @@
"@sendbird/chat": "^4.2.3",
"css-vars-ponyfill": "^2.3.2",
"date-fns": "^2.16.1",
"lamejs": "^1.2.1",
"prop-types": "^15.7.2"
},
"bugs": {
Expand Down
15 changes: 15 additions & 0 deletions scripts/index_d_ts
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,9 @@ declare module "SendbirdUIKitGlobal" {
renderMessageInput?: () => React.ReactNode | React.ReactElement;
renderTypingIndicator?: () => React.ReactNode | React.ReactElement;
renderCustomSeparator?: (props: RenderCustomSeparatorProps) => React.ReactNode | React.ReactElement;
renderFileUploadIcon?: () => React.ReactElement;
renderVoiceMessageIcon?: () => React.ReactElement;
renderSendMessageIcon?: () => React.ReactElement;
}

export type CoreMessageType = AdminMessage | UserMessage | FileMessage;
Expand Down Expand Up @@ -576,6 +579,9 @@ declare module "SendbirdUIKitGlobal" {
// value is removed when channelURL changes
value?: string;
ref?: React.MutableRefObject<any>;
renderFileUploadIcon?: () => React.ReactElement;
renderVoiceMessageIcon?: () => React.ReactElement;
renderSendMessageIcon?: () => React.ReactElement;
};

export type MessageListProps = {
Expand Down Expand Up @@ -984,6 +990,9 @@ declare module "SendbirdUIKitGlobal" {
renderCustomSeparator?: () => React.ReactElement;
renderParentMessageInfoPlaceholder?: (type: ParentMessageStateTypes) => React.ReactElement;
renderThreadListPlaceHolder?: (type: ThreadListStateTypes) => React.ReactElement;
renderFileUploadIcon?: () => React.ReactElement;
renderVoiceMessageIcon?: () => React.ReactElement;
renderSendMessageIcon?: () => React.ReactElement;
}

type EventType = React.MouseEvent<HTMLDivElement | HTMLButtonElement> | React.KeyboardEvent<HTMLDivElement>;
Expand Down Expand Up @@ -1030,6 +1039,9 @@ declare module "SendbirdUIKitGlobal" {

export interface ThreadMessageInputProps {
className?: string;
renderFileUploadIcon?: () => React.ReactElement;
renderVoiceMessageIcon?: () => React.ReactElement;
renderSendMessageIcon?: () => React.ReactElement;
}

/**
Expand Down Expand Up @@ -2009,6 +2021,9 @@ declare module '@sendbird/uikit-react/ui/MessageInput' {
onMentionedUserIdsUpdated?: (userIds: Array<string>) => void,
onKeyUp?: (e: React.KeyboardEvent<HTMLDivElement>) => void,
onKeyDown?: (e: React.KeyboardEvent<HTMLDivElement>) => void,
renderFileUploadIcon?: () => React.ReactElement;
renderVoiceMessageIcon?: () => React.ReactElement;
renderSendMessageIcon?: () => React.ReactElement;
}
const MessageInput: React.FC<MessageInputProps>;
export default MessageInput;
Expand Down
132 changes: 132 additions & 0 deletions src/hooks/VoicePlayer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import React, { createContext, useCallback, useContext, useState } from 'react';
import {
VoicePlayerEvent,
VoicePlayerEventParams,
VoicePlayerEventStorage,
VoicePlayerEventTypes,
} from './voicePlayerEvent';

const noop = () => {/* noop */ };

// VoicePlayerProvider interface
export interface VoicePlayerProps {
children: React.ReactElement;
}
export interface VoicePlayerPlayProps {
audioFile: File;
playbackTime: number;
groupKey: string;
}
export interface VoicePlayerContext {
play: (props: VoicePlayerPlayProps) => void;
stop: (groupKey?: string) => void;
addEventHandler: (props: VoicePlayerEvent) => void;
removeEventHandler: (groupKey: string, handlerId: string) => void;
}

const VoicePlayerContext = createContext<VoicePlayerContext>({
play: noop,
stop: noop,
addEventHandler: noop,
removeEventHandler: noop,
});

export const VoicePlayerProvider = ({
children,
}: VoicePlayerProps): React.ReactElement => {
const [eventStorage, setEventStorage] = useState<VoicePlayerEventStorage>({});
const [currentPlayer, setAudioPlayer] = useState<HTMLAudioElement>(null);
const [currentGroupKey, setCurrentGroupKey] = useState<string>('');

const addEventHandler = (event: VoicePlayerEvent): void => {
const { groupKey } = event;
setEventStorage((storage) => {
if (!storage?.[groupKey]) {
storage[groupKey] = [];
}
storage?.[groupKey].push(event);
return storage;
});
};
const removeEventHandler = (groupKey: string, handlerId: string): void => {
setEventStorage((storage) => {
if (!Array.isArray(storage?.[groupKey])) {
return storage;
}
return ({
...storage,
[groupKey]: storage[groupKey].filter(({ id }) => id !== handlerId),
});
});
};
const triggerEvent = useCallback((eventType: VoicePlayerEventTypes, payload: VoicePlayerEventParams): void => {
const { groupKey } = payload;
if (Array.isArray(eventStorage?.[groupKey])) {
eventStorage[groupKey].map((playerEvent) => {
playerEvent?.[eventType]?.(payload);
});
}
}, [eventStorage]);
const clearStates = (): void => {
setAudioPlayer(null);
setCurrentGroupKey('');
};

const stop = useCallback((groupKey?: string): void => {
if (groupKey === undefined || (groupKey?.length > 0 && groupKey === currentGroupKey)) {
currentPlayer?.pause();
clearStates();
}
}, [currentPlayer, currentGroupKey]);
const play = ({
audioFile,
playbackTime,
groupKey,
}: VoicePlayerPlayProps): void => {
if (currentPlayer || currentGroupKey) {
stop();
}

const audioPlayer = new Audio(URL?.createObjectURL?.(audioFile));
audioPlayer.currentTime = playbackTime;
audioPlayer.volume = 1;
audioPlayer.loop = false;
audioPlayer.onplaying = () => {
triggerEvent(VoicePlayerEventTypes.STARTED, {
groupKey,
playbackTime: audioPlayer?.currentTime,
duration: audioPlayer?.duration,
});
};
audioPlayer.onpause = () => {
triggerEvent(VoicePlayerEventTypes.STOPPED, {
groupKey,
playbackTime: audioPlayer?.currentTime,
duration: audioPlayer?.duration,
});
};
audioPlayer.ontimeupdate = () => {
triggerEvent(VoicePlayerEventTypes.TIME_UPDATED, {
groupKey,
playbackTime: audioPlayer?.currentTime,
duration: audioPlayer?.duration,
});
};
audioPlayer?.play();
setAudioPlayer(audioPlayer);
setCurrentGroupKey(groupKey);
};

return (
<VoicePlayerContext.Provider value={{
play,
stop,
addEventHandler,
removeEventHandler,
}}>
{children}
</VoicePlayerContext.Provider>
);
};

export const useVoicePlayerContext = (): VoicePlayerContext => useContext(VoicePlayerContext);
Loading