import React, { Fragment } from 'react'; import { useMedia } from 'react-use'; import { HMSException, HMSSimulcastLayerDefinition, HMSTrackID, HMSVideoTrack, selectAvailableRoleNames, selectPermissions, selectSessionStore, selectTrackByID, useCustomEvent, useHMSActions, useHMSStore, useRemoteAVToggle, } from '@100mslive/react-sdk'; import { MicOffIcon, MicOnIcon, PencilIcon, PersonSettingsIcon, PinIcon, RemoveUserIcon, ShareScreenIcon, ShrinkIcon, SpeakerIcon, StarIcon, VideoOffIcon, VideoOnIcon, } from '@100mslive/react-icons'; import { Box, Flex } from '../../../Layout'; import { Slider } from '../../../Slider'; import { Text } from '../../../Text'; import { config as cssConfig } from '../../../Theme'; import { StyledMenuTile } from '../../../TileMenu'; import { useHMSPrebuiltContext } from '../../AppContext'; // @ts-ignore import { ToastManager } from '../Toast/ToastManager'; // @ts-ignore import { useSetAppDataByKey } from '../AppData/useUISettings'; // @ts-ignore import { useDropdownSelection } from '../hooks/useDropdownSelection'; import { getDragClassName } from './utils'; import { APP_DATA, isIOS, REMOTE_STOP_SCREENSHARE_TYPE, SESSION_STORE_KEY } from '../../common/constants'; export const isSameTile = ({ trackId, videoTrackID, audioTrackID, }: { trackId: HMSTrackID; videoTrackID?: string; audioTrackID?: string; }) => !!trackId && ((!!videoTrackID && videoTrackID === trackId) || (!!audioTrackID && audioTrackID === trackId)); const spacingCSS = { '@md': { my: '$8', fontWeight: '$semiBold', fontSize: 'sm' } }; const SpotlightActions = ({ peerId, onSpotLightClick = () => { return; }, }: { peerId: string; onSpotLightClick: () => void; }) => { const hmsActions = useHMSActions(); const spotlightPeerId = useHMSStore(selectSessionStore(SESSION_STORE_KEY.SPOTLIGHT)); const isTileSpotlighted = spotlightPeerId === peerId; const dragClassName = getDragClassName(); const setSpotlightPeerId = (peerIdToSpotlight?: string) => hmsActions.sessionStore .set(SESSION_STORE_KEY.SPOTLIGHT, peerIdToSpotlight) .catch((err: HMSException) => ToastManager.addToast({ title: err.description })); return ( { if (isTileSpotlighted) { setSpotlightPeerId(); } else { setSpotlightPeerId(peerId); } onSpotLightClick(); }} > {isTileSpotlighted ? 'Remove from Spotlight' : 'Spotlight Tile for everyone'} ); }; const PinActions = ({ audioTrackID, videoTrackID }: { videoTrackID: string; audioTrackID: string }) => { const [pinnedTrackId, setPinnedTrackId] = useSetAppDataByKey(APP_DATA.pinnedTrackId); const dragClassName = getDragClassName(); const isTilePinned = isSameTile({ trackId: pinnedTrackId, videoTrackID, audioTrackID, }); return ( <> (isTilePinned ? setPinnedTrackId() : setPinnedTrackId(videoTrackID || audioTrackID))} > {isTilePinned ? 'Unpin' : 'Pin'} Tile for myself ); }; const MinimiseInset = () => { const [minimised, setMinimised] = useSetAppDataByKey(APP_DATA.minimiseInset); const dragClassName = getDragClassName(); return ( <> setMinimised(!minimised)}> {minimised ? 'Show' : 'Minimise'} your video ); }; const SimulcastLayers = ({ trackId }: { trackId: HMSTrackID }) => { const track: HMSVideoTrack = useHMSStore(selectTrackByID(trackId)) as HMSVideoTrack; const actions = useHMSActions(); const bg = useDropdownSelection(); if (!track?.layerDefinitions?.length || track.degraded || !track.enabled) { return null; } const currentLayer = track.layerDefinitions.find((layer: HMSSimulcastLayerDefinition) => layer.layer === track.layer); const dragClassName = getDragClassName(); return ( Select maximum resolution {track.layerDefinitions.map((layer: HMSSimulcastLayerDefinition) => { return ( { await actions.setPreferredLayer(trackId, layer.layer); }} css={{ justifyContent: 'space-between', bg: track.preferredLayer === layer.layer ? bg : undefined, '&:hover': { bg: track.preferredLayer === layer.layer ? bg : undefined, }, }} > {layer.layer} {layer.resolution.width}x{layer.resolution.height} ); })} Currently streaming: {currentLayer ? ( <> {track.layer} ({currentLayer.resolution.width}x{currentLayer.resolution.height}) ) : ( '-' )} ); }; export const TileMenuContent = ({ videoTrackID, audioTrackID, isLocal, isScreenshare, showSpotlight, showPinAction, peerID, canMinimise, closeSheetOnClick = () => { return; }, openNameChangeModal = () => { return; }, openRoleChangeModal = () => { return; }, }: { videoTrackID: string; audioTrackID: string; isLocal: boolean; isScreenshare: boolean; showSpotlight: boolean; showPinAction: boolean; peerID: string; canMinimise?: boolean; closeSheetOnClick?: () => void; openNameChangeModal?: () => void; openRoleChangeModal?: () => void; }) => { const actions = useHMSActions(); const dragClassName = getDragClassName(); const permissions = useHMSStore(selectPermissions); const canChangeRole = !!permissions?.changeRole; const removeOthers = !!permissions?.removeOthers; const { userName } = useHMSPrebuiltContext(); const roles = useHMSStore(selectAvailableRoleNames); const { isAudioEnabled, isVideoEnabled, setVolume, toggleAudio, toggleVideo, volume } = useRemoteAVToggle( audioTrackID, videoTrackID, ); const { sendEvent } = useCustomEvent({ type: REMOTE_STOP_SCREENSHARE_TYPE, }); const isMobile = useMedia(cssConfig.media.md); if (isLocal) { return showPinAction || canMinimise || !userName || showSpotlight ? ( <> {showPinAction && } {showSpotlight && closeSheetOnClick()} />} {canMinimise && } {!userName && ( { openNameChangeModal(); closeSheetOnClick(); }} > Change Name )} ) : null; } return ( <> {toggleVideo ? ( { toggleVideo(); closeSheetOnClick(); }} data-testid={isVideoEnabled ? 'mute_video_participant_btn' : 'unmute_video_participant_btn'} > {isVideoEnabled ? : } {isVideoEnabled ? 'Mute Video' : 'Request to Unmute Video'} ) : null} {toggleAudio ? ( { toggleAudio(); closeSheetOnClick(); }} data-testid={isAudioEnabled ? 'mute_audio_participant_btn' : 'unmute_audio_participant_btn'} > {isAudioEnabled ? : } {isAudioEnabled ? 'Mute Audio' : 'Request to Unmute Audio'} ) : null} {!isScreenshare && canChangeRole && roles.length > 1 ? ( { openRoleChangeModal(); closeSheetOnClick(); }} data-testid="change_role_btn" > Switch Role ) : null} {!isIOS && audioTrackID ? ( Volume ({volume}) setVolume?.(e[0])} /> ) : null} {showPinAction && ( <> {showSpotlight && closeSheetOnClick()} />} )} {isMobile ? null : } {removeOthers ? ( { try { await actions.removePeer(peerID, ''); } catch (error) { // TODO: Toast here } closeSheetOnClick(); }} data-testid="remove_participant_btn" > Remove Participant ) : null} {removeOthers && isScreenshare ? ( { sendEvent({}); closeSheetOnClick(); }} css={spacingCSS} > Stop Screenshare ) : null} ); };