feat(livekit): add chat count in outside

perf/livekit-chat-count
moonrailgun 2 years ago
parent 584f7f3469
commit bd2c161f61

@ -2,21 +2,11 @@ import type {
ChatMessage, ChatMessage,
ReceivedChatMessage, ReceivedChatMessage,
} from '@livekit/components-core'; } from '@livekit/components-core';
import { setupChat } from '@livekit/components-core'; import { ChatEntry, MessageFormatter } from '@livekit/components-react';
import {
ChatEntry,
MessageFormatter,
useRoomContext,
} from '@livekit/components-react';
import * as React from 'react'; import * as React from 'react';
import { Translate } from '../../translate'; import { Translate } from '../../translate';
import { cloneSingleChild } from '../../utils/common'; import { cloneSingleChild } from '../../utils/common';
import { useObservableState } from '../../utils/useObservableState'; import { useChatContext } from './ChatContext';
// import { useRoomContext } from '../context';
// import { useObservableState } from '../hooks/internal/useObservableState';
// import { cloneSingleChild } from '../utils';
// import type { MessageFormatter } from '../components/ChatEntry';
// import { ChatEntry } from '../components/ChatEntry';
export type { ChatMessage, ReceivedChatMessage }; export type { ChatMessage, ReceivedChatMessage };
@ -25,22 +15,6 @@ export interface ChatProps extends React.HTMLAttributes<HTMLDivElement> {
messageFormatter?: MessageFormatter; messageFormatter?: MessageFormatter;
} }
/** @public */
export function useChat() {
const room = useRoomContext();
const [setup, setSetup] = React.useState<ReturnType<typeof setupChat>>();
const isSending = useObservableState(setup?.isSendingObservable, false);
const chatMessages = useObservableState(setup?.messageObservable, []);
React.useEffect(() => {
const setupChatReturn = setupChat(room);
setSetup(setupChatReturn);
return setupChatReturn.destroy;
}, [room]);
return { send: setup?.send, chatMessages, isSending };
}
/** /**
* The Chat component adds a basis chat functionality to the LiveKit room. The messages are distributed to all participants * The Chat component adds a basis chat functionality to the LiveKit room. The messages are distributed to all participants
* in the room. Only users who are in the room at the time of dispatch will receive the message. * in the room. Only users who are in the room at the time of dispatch will receive the message.
@ -56,7 +30,7 @@ export function useChat() {
export function Chat({ messageFormatter, ...props }: ChatProps) { export function Chat({ messageFormatter, ...props }: ChatProps) {
const inputRef = React.useRef<HTMLInputElement>(null); const inputRef = React.useRef<HTMLInputElement>(null);
const ulRef = React.useRef<HTMLUListElement>(null); const ulRef = React.useRef<HTMLUListElement>(null);
const { send, chatMessages, isSending } = useChat(); const { send, chatMessages, isSending } = useChatContext();
async function handleSubmit(event: React.FormEvent) { async function handleSubmit(event: React.FormEvent) {
event.preventDefault(); event.preventDefault();

@ -0,0 +1,47 @@
import { useRoomContext } from '@livekit/components-react';
import React, { useContext, useEffect, useState } from 'react';
import { ReceivedChatMessage, setupChat } from '@livekit/components-core';
import { useObservableState } from '../../utils/useObservableState';
const ChatContext = React.createContext({
send: async (message: string) => {},
chatMessages: [] as ReceivedChatMessage[],
isSending: false,
});
ChatContext.displayName = 'ChatContext';
export const ChatProvider: React.FC<React.PropsWithChildren> = React.memo(
(props) => {
const chatContext = useSetupChat();
return (
<ChatContext.Provider value={chatContext}>
{props.children}
</ChatContext.Provider>
);
}
);
ChatProvider.displayName = 'ChatProvider';
function useSetupChat() {
const room = useRoomContext();
const [setup, setSetup] = useState<ReturnType<typeof setupChat>>();
const isSending = useObservableState(setup?.isSendingObservable, false);
const chatMessages = useObservableState<ReceivedChatMessage[]>(
setup?.messageObservable,
[]
);
useEffect(() => {
const setupChatReturn = setupChat(room);
setSetup(setupChatReturn);
return setupChatReturn.destroy;
}, [room]);
return { send: setup?.send, chatMessages, isSending };
}
export function useChatContext() {
return useContext(ChatContext);
}

@ -15,6 +15,7 @@ import { Translate } from '../../translate';
import { useMediaQuery } from '../../utils/useMediaQuery'; import { useMediaQuery } from '../../utils/useMediaQuery';
import { ChatIcon } from './icons/ChatIcon'; import { ChatIcon } from './icons/ChatIcon';
import { LeaveIcon } from './icons/LeaveIcon'; import { LeaveIcon } from './icons/LeaveIcon';
import { useChatContext } from './ChatContext';
/** @public */ /** @public */
export type ControlBarControls = { export type ControlBarControls = {
@ -58,6 +59,7 @@ export function ControlBar({ variation, controls, ...props }: ControlBarProps) {
const isTooLittleSpace = useMediaQuery( const isTooLittleSpace = useMediaQuery(
`(max-width: ${isChatOpen ? 1000 : 760}px)` `(max-width: ${isChatOpen ? 1000 : 760}px)`
); );
const { chatMessages } = useChatContext();
const defaultVariation = isTooLittleSpace ? 'minimal' : 'verbose'; const defaultVariation = isTooLittleSpace ? 'minimal' : 'verbose';
variation ??= defaultVariation; variation ??= defaultVariation;
@ -137,6 +139,9 @@ export function ControlBar({ variation, controls, ...props }: ControlBarProps) {
<ChatToggle> <ChatToggle>
{showIcon && <ChatIcon />} {showIcon && <ChatIcon />}
{showText && Translate.chat} {showText && Translate.chat}
{Array.isArray(chatMessages) && chatMessages.length > 0 && (
<span>({chatMessages.length})</span>
)}
</ChatToggle> </ChatToggle>
)} )}

@ -28,6 +28,7 @@ import { CarouselLayout } from './CarouselLayout';
import { ControlBar } from './ControlBar'; import { ControlBar } from './ControlBar';
import { Chat } from './Chat'; import { Chat } from './Chat';
import { FocusLayout } from './FocusLayout'; import { FocusLayout } from './FocusLayout';
import { ChatProvider } from './ChatContext';
/** /**
* @public * @public
@ -124,32 +125,34 @@ export const VideoConference: React.FC<VideoConferenceProps> = React.memo(
// onPinChange={handleFocusStateChange} // onPinChange={handleFocusStateChange}
onWidgetChange={widgetUpdate} onWidgetChange={widgetUpdate}
> >
<div className="lk-video-conference-inner"> <ChatProvider>
{!focusTrack ? ( <div className="lk-video-conference-inner">
<div className="lk-grid-layout-wrapper"> {!focusTrack ? (
<GridLayout tracks={tracks}> <div className="lk-grid-layout-wrapper">
<ParticipantTile /> <GridLayout tracks={tracks}>
</GridLayout>
</div>
) : (
<div className="lk-focus-layout-wrapper">
<FocusLayoutContainer>
<CarouselLayout tracks={carouselTracks}>
<ParticipantTile /> <ParticipantTile />
</CarouselLayout> </GridLayout>
</div>
) : (
<div className="lk-focus-layout-wrapper">
<FocusLayoutContainer>
<CarouselLayout tracks={carouselTracks}>
<ParticipantTile />
</CarouselLayout>
{focusTrack && <FocusLayout track={focusTrack} />} {focusTrack && <FocusLayout track={focusTrack} />}
</FocusLayoutContainer> </FocusLayoutContainer>
</div> </div>
)} )}
<ControlBar controls={{ chat: true }} /> <ControlBar controls={{ chat: true }} />
</div> </div>
<Chat <Chat
style={{ display: widgetState.showChat ? 'flex' : 'none' }} style={{ display: widgetState.showChat ? 'flex' : 'none' }}
messageFormatter={chatMessageFormatter} messageFormatter={chatMessageFormatter}
/> />
</ChatProvider>
</LayoutContextProvider> </LayoutContextProvider>
)} )}

Loading…
Cancel
Save