import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'react'; import { useMeasure, useMedia } from 'react-use'; import { HMSRoomState, selectAppData, selectIsLocalVideoEnabled, selectIsVBEnabled, selectLocalPeer, selectRoomState, selectVideoTrackByID, useAVToggle, useAwayNotifications, useHMSStore, useParticipants, usePreviewJoin, useRecordingStreaming, } from '@100mslive/react-sdk'; import { MicOffIcon, SettingsIcon } from '@100mslive/react-icons'; import { Avatar, Box, config as cssConfig, Flex, flexCenter, styled, StyledVideoTile, Text, Video } from '../../..'; import { AudioLevel } from '../../../AudioLevel'; import { useHMSPrebuiltContext } from '../../AppContext'; import IconButton from '../../IconButton'; import SidePane from '../../layouts/SidePane'; import { AudioVideoToggle, NoiseCancellation } from '../AudioVideoToggle'; import Chip from '../Chip'; import TileConnection from '../Connection/TileConnection'; import FullPageProgress from '../FullPageProgress'; // @ts-ignore: No implicit Any import { Logo } from '../Header/HeaderComponents'; // @ts-ignore: No implicit Any import SettingsModal from '../Settings/SettingsModal'; import { VBToggle } from '../VirtualBackground/VBToggle'; import PreviewForm from './PreviewForm'; import { useRoomLayoutPreviewScreen } from '../../provider/roomLayoutProvider/hooks/useRoomLayoutScreen'; import { useAuthToken, useUISettings, // @ts-ignore: No implicit Any } from '../AppData/useUISettings'; // @ts-ignore: No implicit Any import { defaultPreviewPreference, UserPreferencesKeys, useUserPreferences } from '../hooks/useUserPreferences'; // @ts-ignore: No implicit Any import { calculateAvatarAndAttribBoxSize, getFormattedCount } from '../../common/utils'; import { APP_DATA, UI_SETTINGS } from '../../common/constants'; const getParticipantChipContent = (peerCount = 0) => { if (peerCount === 0) { return 'You are the first to join'; } const formattedNum = getFormattedCount(peerCount); return `${formattedNum} other${parseInt(formattedNum) === 1 ? '' : 's'} in the session`; }; const useLocalTileAspectRatio = () => { const localPeer = useHMSStore(selectLocalPeer); const videoTrack = useHMSStore(selectVideoTrackByID(localPeer?.videoTrack)); const isMobile = useMedia(cssConfig.media.md); let aspectRatio = 0; if (videoTrack?.width && videoTrack?.height) { aspectRatio = videoTrack.width / videoTrack.height; } else { aspectRatio = isMobile ? 9 / 16 : 16 / 9; } return aspectRatio.toString(); }; const PreviewJoin = ({ skipPreview, initialName, asRole, }: { skipPreview?: boolean; initialName?: string; asRole?: string; }) => { const [previewPreference, setPreviewPreference] = useUserPreferences( UserPreferencesKeys.PREVIEW, defaultPreviewPreference, ); const { isStreamingOn } = useRecordingStreaming(); const authToken = useAuthToken(); const [name, setName] = useState(initialName || previewPreference.name); const { toggleAudio, toggleVideo } = useAVToggle(); const [previewError, setPreviewError] = useState(false); const { endpoints } = useHMSPrebuiltContext(); const { peerCount } = useParticipants(); const loadingEffects = useHMSStore(selectAppData(APP_DATA.loadingEffects)); const { enableJoin, preview, join } = usePreviewJoin({ name, token: authToken, initEndpoint: endpoints?.init, initialSettings: { isAudioMuted: skipPreview || previewPreference.isAudioMuted, isVideoMuted: skipPreview || previewPreference.isVideoMuted, speakerAutoSelectionBlacklist: ['Yeti Stereo Microphone'], }, captureNetworkQualityInPreview: true, handleError: (_, method) => { if (method === 'preview') { setPreviewError(true); } }, asRole, }); const { requestPermission } = useAwayNotifications(); const roomState = useHMSStore(selectRoomState); const savePreferenceAndJoin = useCallback(() => { setPreviewPreference({ name, }); join(); }, [join, name, setPreviewPreference]); const { elements = {} } = useRoomLayoutPreviewScreen(); const { preview_header: previewHeader = {}, virtual_background } = elements || {}; const aspectRatio = useLocalTileAspectRatio(); useEffect(() => { if (authToken) { if (skipPreview) { savePreferenceAndJoin(); } else { preview().then(() => requestPermission()); } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [authToken, skipPreview]); useEffect(() => { if (initialName) { setName(initialName); } }, [initialName]); return roomState === HMSRoomState.Preview ? ( {toggleVideo ? null : } {previewHeader.title} {previewHeader.sub_title} {isStreamingOn ? ( } /> ) : null} {toggleVideo ? : null} ) : ( ); }; const Container = styled('div', { width: '100%', ...flexCenter, flexDirection: 'column', px: '$10', }); export const PreviewTile = ({ name, error }: { name: string; error?: boolean }) => { const localPeer = useHMSStore(selectLocalPeer); const { isLocalAudioEnabled, toggleAudio } = useAVToggle(); const isVideoOn = useHMSStore(selectIsLocalVideoEnabled); const mirrorLocalVideo = useUISettings(UI_SETTINGS.mirrorLocalVideo); const trackSelector = selectVideoTrackByID(localPeer?.videoTrack); const track = useHMSStore(trackSelector); const showMuteIcon = !isLocalAudioEnabled || !toggleAudio; const aspectRatio = useLocalTileAspectRatio(); const [ref, { width: calculatedWidth, height: calculatedHeight }] = useMeasure(); const [avatarSize, attribBoxSize] = useMemo( () => calculateAvatarAndAttribBoxSize(calculatedWidth, calculatedHeight), [calculatedWidth, calculatedHeight], ); return ( {localPeer ? ( <> ); }; export const PreviewControls = ({ hideSettings, vbEnabled }: { hideSettings: boolean; vbEnabled: boolean }) => { const isMobile = useMedia(cssConfig.media.md); const isVBEnabledForUser = useHMSStore(selectIsVBEnabled); return ( {vbEnabled && isVBEnabledForUser ? : null} {isMobile && } {!hideSettings ? : null} ); }; export const PreviewSettings = React.memo(() => { const [open, setOpen] = useState(false); return ( setOpen(value => !value)}> {open && } ); }); export default PreviewJoin;