@azure/communication-react
Version:
React library for building modern communication user experiences utilizing Azure Communication Services
117 lines • 8.58 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import React, { useCallback, useMemo, useRef } from 'react';
import { VideoGallery, Announcer } from "../../../../../react-components/src";
import { _useContainerWidth, _useContainerHeight } from "../../../../../react-components/src";
import { usePropsFor } from '../hooks/usePropsFor';
import { AvatarPersona } from '../../common/AvatarPersona';
import { mergeStyles, Stack } from '@fluentui/react';
import { useHandlers } from '../hooks/useHandlers';
import { useSelector } from '../hooks/useSelector';
import { localVideoCameraCycleButtonSelector } from '../selectors/LocalVideoTileSelector';
import { LocalVideoCameraCycleButton } from "../../../../../react-components/src";
import { useParticipantChangedAnnouncement } from '../utils/MediaGalleryUtils';
import { useLocalSpotlightCallbacksWithPrompt, useRemoteSpotlightCallbacksWithPrompt } from '../utils/spotlightUtils';
import { getCapabilites, getIsRoomsCall, getReactionResources, getRole } from '../selectors/baseSelectors';
const VideoGalleryStyles = {
root: {
height: '100%',
minHeight: '10rem',
// space affordance to ensure media gallery is never collapsed
minWidth: '6rem'
}
};
const localVideoViewOptions = {
scalingMode: 'Crop',
isMirrored: true
};
const remoteVideoViewOptions = {
scalingMode: 'Crop'
};
/**
* @private
*/
export const MediaGallery = (props) => {
var _a, _b;
const { pinnedParticipants = [], setPinnedParticipants, setIsPromptOpen, setPromptProps, hideSpotlightButtons, videoTilesOptions, captionsOptions, compositeContainerAspectRatio } = props;
const videoGalleryProps = usePropsFor(VideoGallery);
const cameraSwitcherCameras = useSelector(localVideoCameraCycleButtonSelector);
const cameraSwitcherCallback = useHandlers(LocalVideoCameraCycleButton);
const announcerString = useParticipantChangedAnnouncement();
const userRole = useSelector(getRole);
const capabilities = useSelector(getCapabilites);
const isRoomsCall = useSelector(getIsRoomsCall);
const reactionResources = useSelector(getReactionResources);
const containerRef = useRef(null);
const containerWidth = _useContainerWidth(containerRef);
const containerHeight = _useContainerHeight(containerRef);
const layoutBasedOnTilePosition = getVideoGalleryLayoutBasedOnLocalOptions((_a = props.localVideoTileOptions) === null || _a === void 0 ? void 0 : _a.position);
const cameraSwitcherProps = useMemo(() => {
return Object.assign(Object.assign({}, cameraSwitcherCallback), cameraSwitcherCameras);
}, [cameraSwitcherCallback, cameraSwitcherCameras]);
const onRenderAvatar = useCallback((userId, options) => {
return React.createElement(Stack, { className: mergeStyles({
position: 'absolute',
height: '100%',
width: '100%'
}) },
React.createElement(Stack, { styles: {
root: {
margin: 'auto',
maxHeight: '100%'
}
} }, (options === null || options === void 0 ? void 0 : options.coinSize) && React.createElement(AvatarPersona, Object.assign({ userId: userId }, options, { dataProvider: props.onFetchAvatarPersonaData }))));
}, [props.onFetchAvatarPersonaData]);
const remoteVideoTileMenuOptions = useMemo(() => {
var _a;
return ((_a = props.remoteVideoTileMenuOptions) === null || _a === void 0 ? void 0 : _a.isHidden) ? false : props.isMobile ? {
kind: 'drawer',
hostId: props.drawerMenuHostId
} : {
kind: 'contextual'
};
}, [(_b = props.remoteVideoTileMenuOptions) === null || _b === void 0 ? void 0 : _b.isHidden, props.isMobile, props.drawerMenuHostId]);
const overflowGalleryPosition = useMemo(() => {
return containerWidth && containerHeight && containerWidth / containerHeight >= 16 / 9 ? 'verticalRight' : 'horizontalBottom';
}, [containerWidth, containerHeight]);
const { onStartLocalSpotlight, onStopLocalSpotlight, onStartRemoteSpotlight, onStopRemoteSpotlight } = videoGalleryProps;
const { onStartLocalSpotlightWithPrompt, onStopLocalSpotlightWithPrompt } = useLocalSpotlightCallbacksWithPrompt(onStartLocalSpotlight, onStopLocalSpotlight, setIsPromptOpen, setPromptProps);
const { onStartRemoteSpotlightWithPrompt, onStopRemoteSpotlightWithPrompt } = useRemoteSpotlightCallbacksWithPrompt(onStartRemoteSpotlight, onStopRemoteSpotlight, setIsPromptOpen, setPromptProps);
const galleryStyles = useMemo(() => {
return Object.assign(Object.assign({}, VideoGalleryStyles), ((captionsOptions === null || captionsOptions === void 0 ? void 0 : captionsOptions.height) === 'full' ? {
root: {
postion: 'absolute'
}
} : {}));
}, [captionsOptions === null || captionsOptions === void 0 ? void 0 : captionsOptions.height]);
const onPinParticipant = useMemo(() => {
return setPinnedParticipants ? (userId) => {
if (!pinnedParticipants.includes(userId)) {
setPinnedParticipants(pinnedParticipants.concat(userId));
}
} : undefined;
}, [setPinnedParticipants, pinnedParticipants]);
const onUnpinParticipant = useMemo(() => {
return setPinnedParticipants ? (userId) => {
setPinnedParticipants(pinnedParticipants.filter(participantId => participantId !== userId));
} : undefined;
}, [setPinnedParticipants, pinnedParticipants]);
const VideoGalleryMemoized = useMemo(() => {
var _a;
const layoutBasedOnUserSelection = () => {
return props.localVideoTileOptions ? layoutBasedOnTilePosition : props.userSetGalleryLayout;
};
return React.createElement(VideoGallery, Object.assign({}, videoGalleryProps, { videoTilesOptions: videoTilesOptions, localVideoViewOptions: localVideoViewOptions, remoteVideoViewOptions: remoteVideoViewOptions, styles: galleryStyles, layout: layoutBasedOnUserSelection(), showCameraSwitcherInLocalPreview: props.isMobile, localVideoCameraCycleButtonProps: cameraSwitcherProps, onRenderAvatar: onRenderAvatar, remoteVideoTileMenu: remoteVideoTileMenuOptions, overflowGalleryPosition: overflowGalleryPosition, localVideoTileSize: props.localVideoTileOptions === false || userRole === 'Consumer' || isRoomsCall && userRole === 'Unknown' ? 'hidden' : props.isMobile && compositeContainerAspectRatio && compositeContainerAspectRatio < 1 ? '9:16' : '16:9', pinnedParticipants: pinnedParticipants, onPinParticipant: onPinParticipant, onUnpinParticipant: onUnpinParticipant, reactionResources: reactionResources, onStartLocalSpotlight: hideSpotlightButtons ? undefined : onStartLocalSpotlightWithPrompt, onStopLocalSpotlight: hideSpotlightButtons ? undefined : onStopLocalSpotlightWithPrompt, onStartRemoteSpotlight: hideSpotlightButtons ? undefined : onStartRemoteSpotlightWithPrompt, onStopRemoteSpotlight: hideSpotlightButtons ? undefined : onStopRemoteSpotlightWithPrompt, onMuteParticipant: ((_a = capabilities === null || capabilities === void 0 ? void 0 : capabilities.muteOthers) === null || _a === void 0 ? void 0 : _a.isPresent) || userRole === 'Unknown' ? videoGalleryProps.onMuteParticipant : undefined, localScreenShareView: props.localScreenShareView }));
}, [videoGalleryProps, videoTilesOptions, galleryStyles, props.isMobile, props.localVideoTileOptions, props.userSetGalleryLayout, cameraSwitcherProps, onRenderAvatar, remoteVideoTileMenuOptions, overflowGalleryPosition, userRole, isRoomsCall, pinnedParticipants, onPinParticipant, onUnpinParticipant, reactionResources, hideSpotlightButtons, onStartLocalSpotlightWithPrompt, onStopLocalSpotlightWithPrompt, onStartRemoteSpotlightWithPrompt, onStopRemoteSpotlightWithPrompt, layoutBasedOnTilePosition, capabilities === null || capabilities === void 0 ? void 0 : capabilities.muteOthers, props.localScreenShareView, compositeContainerAspectRatio]);
return React.createElement("div", { ref: containerRef, style: mediaGalleryContainerStyles },
React.createElement(Announcer, { announcementString: announcerString, ariaLive: 'polite' }),
VideoGalleryMemoized);
};
const mediaGalleryContainerStyles = {
width: '100%',
height: '100%'
};
const getVideoGalleryLayoutBasedOnLocalOptions = (localTileOptions) => {
return localTileOptions === 'grid' ? 'default' : 'floatingLocalVideo';
};
//# sourceMappingURL=MediaGallery.js.map