From 756be17cc7ad8344c8afb4803630f5be595fa642 Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Wed, 18 Sep 2024 16:49:36 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(frontend)=20introduce=20a=20side=20pa?= =?UTF-8?q?nel=20for=20effects?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It simply renders the video track if enabled. It's a basis for building the 'blur your screen' feature. More in the upcoming commits. --- .../rooms/livekit/components/Effects.tsx | 68 +++++++++++++++++++ .../rooms/livekit/components/SidePanel.tsx | 4 +- .../controls/Options/OptionsMenuItems.tsx | 5 +- .../livekit/hooks/useWidgetInteraction.ts | 10 +++ src/frontend/src/locales/de/rooms.json | 9 ++- src/frontend/src/locales/en/rooms.json | 9 ++- src/frontend/src/locales/fr/rooms.json | 9 ++- src/frontend/src/stores/layout.ts | 2 +- 8 files changed, 106 insertions(+), 10 deletions(-) create mode 100644 src/frontend/src/features/rooms/livekit/components/Effects.tsx diff --git a/src/frontend/src/features/rooms/livekit/components/Effects.tsx b/src/frontend/src/features/rooms/livekit/components/Effects.tsx new file mode 100644 index 00000000..4037d069 --- /dev/null +++ b/src/frontend/src/features/rooms/livekit/components/Effects.tsx @@ -0,0 +1,68 @@ +import { useEffect, useRef } from 'react' +import { useLocalParticipant } from '@livekit/components-react' +import { LocalVideoTrack } from 'livekit-client' +import { Div, P } from '@/primitives' +import { useTranslation } from 'react-i18next' + +export const Effects = () => { + const { t } = useTranslation('rooms', { keyPrefix: 'effects' }) + const { isCameraEnabled, cameraTrack } = useLocalParticipant() + const videoRef = useRef(null) + + const localCameraTrack = cameraTrack?.track as LocalVideoTrack + + useEffect(() => { + const videoElement = videoRef.current + + const attachVideoTrack = async () => { + if (!videoElement) return + localCameraTrack?.attach(videoElement) + } + + attachVideoTrack() + + return () => { + if (!videoElement) return + localCameraTrack.detach(videoElement) + } + }, [localCameraTrack, isCameraEnabled]) + + return ( +
+ {localCameraTrack && isCameraEnabled ? ( +
+ ) +} diff --git a/src/frontend/src/features/rooms/livekit/components/SidePanel.tsx b/src/frontend/src/features/rooms/livekit/components/SidePanel.tsx index febf6489..7967141b 100644 --- a/src/frontend/src/features/rooms/livekit/components/SidePanel.tsx +++ b/src/frontend/src/features/rooms/livekit/components/SidePanel.tsx @@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next' import { ParticipantsList } from './controls/Participants/ParticipantsList' import { useWidgetInteraction } from '../hooks/useWidgetInteraction' import { ReactNode } from 'react' +import { Effects } from './Effects' type StyledSidePanelProps = { title: string @@ -65,7 +66,7 @@ export const SidePanel = () => { const layoutSnap = useSnapshot(layoutStore) const sidePanel = layoutSnap.sidePanel - const { isParticipantsOpen } = useWidgetInteraction() + const { isParticipantsOpen, isEffectsOpen } = useWidgetInteraction() const { t } = useTranslation('rooms', { keyPrefix: 'sidePanel' }) if (!sidePanel) { @@ -81,6 +82,7 @@ export const SidePanel = () => { })} > {isParticipantsOpen && } + {isEffectsOpen && } ) } diff --git a/src/frontend/src/features/rooms/livekit/components/controls/Options/OptionsMenuItems.tsx b/src/frontend/src/features/rooms/livekit/components/controls/Options/OptionsMenuItems.tsx index eec8035d..661bd567 100644 --- a/src/frontend/src/features/rooms/livekit/components/controls/Options/OptionsMenuItems.tsx +++ b/src/frontend/src/features/rooms/livekit/components/controls/Options/OptionsMenuItems.tsx @@ -10,6 +10,7 @@ import { useTranslation } from 'react-i18next' import { Dispatch, SetStateAction } from 'react' import { DialogState } from './OptionsButton' import { Separator } from '@/primitives/Separator' +import { useWidgetInteraction } from '../../../hooks/useWidgetInteraction' // @todo try refactoring it to use MenuList component export const OptionsMenuItems = ({ @@ -18,7 +19,7 @@ export const OptionsMenuItems = ({ onOpenDialog: Dispatch> }) => { const { t } = useTranslation('rooms', { keyPrefix: 'options.items' }) - + const { toggleEffects } = useWidgetInteraction() return (
console.log('open dialog')} + onAction={() => toggleEffects()} className={menuItemRecipe({ icon: true })} > diff --git a/src/frontend/src/features/rooms/livekit/hooks/useWidgetInteraction.ts b/src/frontend/src/features/rooms/livekit/hooks/useWidgetInteraction.ts index 1c158709..8e44171d 100644 --- a/src/frontend/src/features/rooms/livekit/hooks/useWidgetInteraction.ts +++ b/src/frontend/src/features/rooms/livekit/hooks/useWidgetInteraction.ts @@ -9,6 +9,7 @@ export const useWidgetInteraction = () => { const sidePanel = layoutSnap.sidePanel const isParticipantsOpen = sidePanel == 'participants' + const isEffectsOpen = sidePanel == 'effects' const toggleParticipants = () => { if (dispatch && state?.showChat) { @@ -26,11 +27,20 @@ export const useWidgetInteraction = () => { } } + const toggleEffects = () => { + if (dispatch && state?.showChat) { + dispatch({ msg: 'toggle_chat' }) + } + layoutStore.sidePanel = isEffectsOpen ? null : 'effects' + } + return { toggleParticipants, toggleChat, + toggleEffects, isChatOpen: state?.showChat, unreadMessages: state?.unreadMessages, isParticipantsOpen, + isEffectsOpen, } } diff --git a/src/frontend/src/locales/de/rooms.json b/src/frontend/src/locales/de/rooms.json index c06c160f..386e268f 100644 --- a/src/frontend/src/locales/de/rooms.json +++ b/src/frontend/src/locales/de/rooms.json @@ -73,12 +73,17 @@ "effects": "" } }, + "effects": { + "activateCamera": "" + }, "sidePanel": { "heading": { - "participants": "" + "participants": "", + "effects": "" }, "content": { - "participants": "" + "participants": "", + "effects": "" }, "closeButton": "" }, diff --git a/src/frontend/src/locales/en/rooms.json b/src/frontend/src/locales/en/rooms.json index 294d2806..2b24508f 100644 --- a/src/frontend/src/locales/en/rooms.json +++ b/src/frontend/src/locales/en/rooms.json @@ -71,12 +71,17 @@ "effects": "Apply effects" } }, + "effects": { + "activateCamera": "Camera is disabled" + }, "sidePanel": { "heading": { - "participants": "Participants" + "participants": "Participants", + "effects": "Effects" }, "content": { - "participants": "participants" + "participants": "participants", + "effects": "effects" }, "closeButton": "Hide {{content}}" }, diff --git a/src/frontend/src/locales/fr/rooms.json b/src/frontend/src/locales/fr/rooms.json index 6f2379f3..f9e7af56 100644 --- a/src/frontend/src/locales/fr/rooms.json +++ b/src/frontend/src/locales/fr/rooms.json @@ -71,12 +71,17 @@ "effects": "Appliquer des effets" } }, + "effects": { + "activateCamera": "Votre camera est désactivée" + }, "sidePanel": { "heading": { - "participants": "Participants" + "participants": "Participants", + "effects": "Effets" }, "content": { - "participants": "les participants" + "participants": "les participants", + "effects": "les effets" }, "closeButton": "Masquer {{content}}" }, diff --git a/src/frontend/src/stores/layout.ts b/src/frontend/src/stores/layout.ts index 70cb4e8d..f8f42994 100644 --- a/src/frontend/src/stores/layout.ts +++ b/src/frontend/src/stores/layout.ts @@ -2,7 +2,7 @@ import { proxy } from 'valtio' type State = { showHeader: boolean - sidePanel: 'participants' | null + sidePanel: 'participants' | 'effects' | null } export const layoutStore = proxy({