Fix issue with screen share
This commit is contained in:
parent
1ae4de54f2
commit
3d7ee93fb3
|
|
@ -1,12 +1,17 @@
|
|||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useParticipants } from '@custom/shared/contexts/ParticipantsProvider';
|
||||
import { useUIState, VIEW_MODE_SPEAKER } from '@custom/shared/contexts/UIStateProvider';
|
||||
import { GridView } from '../GridView/GridView';
|
||||
import { SpeakerView } from '../SpeakerView';
|
||||
|
||||
export const VideoView = () => {
|
||||
const { viewMode } = useUIState();
|
||||
const { participants } = useParticipants();
|
||||
const { viewMode, setIsShowingScreenshare } = useUIState();
|
||||
const { participants, screens } = useParticipants();
|
||||
|
||||
useEffect(() => {
|
||||
const hasScreens = screens.length > 0;
|
||||
setIsShowingScreenshare(hasScreens);
|
||||
}, [screens, setIsShowingScreenshare]);
|
||||
|
||||
if (!participants.length) return null;
|
||||
return viewMode === VIEW_MODE_SPEAKER ? <SpeakerView />: <GridView />;
|
||||
|
|
|
|||
|
|
@ -295,25 +295,25 @@ export const GridView = ({
|
|||
|
||||
return (
|
||||
<div ref={gridRef} className="grid">
|
||||
<Button
|
||||
className="page-button prev"
|
||||
disabled={!(pages > 1 && page > 1)}
|
||||
type="button"
|
||||
onClick={handlePrevClick}
|
||||
>
|
||||
<IconArrow />
|
||||
</Button>
|
||||
|
||||
{(pages > 1 && page > 1) && (
|
||||
<Button
|
||||
className="page-button prev"
|
||||
type="button"
|
||||
onClick={handlePrevClick}
|
||||
>
|
||||
<IconArrow />
|
||||
</Button>
|
||||
)}
|
||||
<div className="tiles">{tiles}</div>
|
||||
|
||||
<Button
|
||||
className="page-button next"
|
||||
disabled={!(pages > 1 && page < pages)}
|
||||
type="button"
|
||||
onClick={handleNextClick}
|
||||
>
|
||||
<IconArrow />
|
||||
</Button>
|
||||
{(pages > 1 && page < pages) && (
|
||||
<Button
|
||||
className="page-button next"
|
||||
type="button"
|
||||
onClick={handleNextClick}
|
||||
>
|
||||
<IconArrow />
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<style jsx>{`
|
||||
.grid {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
import { useState } from 'react';
|
||||
import Tile from '@custom/shared/components/Tile';
|
||||
|
||||
export const ScreenPinTile = ({
|
||||
height,
|
||||
hideName = false,
|
||||
item,
|
||||
maxWidth,
|
||||
ratio: initialRatio,
|
||||
}) => {
|
||||
const [ratio, setRatio] = useState(initialRatio);
|
||||
const handleResize = (aspectRatio) => setRatio(aspectRatio);
|
||||
|
||||
if (item.isScreenshare) {
|
||||
return (
|
||||
<Tile
|
||||
aspectRatio={initialRatio}
|
||||
hideName={hideName}
|
||||
participant={item}
|
||||
mirrored={false}
|
||||
style={{
|
||||
height,
|
||||
maxWidth,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Tile
|
||||
aspectRatio={ratio}
|
||||
participant={item}
|
||||
onVideoResize={handleResize}
|
||||
style={{
|
||||
maxHeight: height,
|
||||
maxWidth: height * ratio,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ScreenPinTile;
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
import { useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { useCallState } from '@custom/shared/contexts/CallProvider';
|
||||
import { useUIState } from '@custom/shared/contexts/UIStateProvider';
|
||||
import { useResize } from '@custom/shared/hooks/useResize';
|
||||
import { useDeepCompareMemo } from 'use-deep-compare';
|
||||
import { ScreenPinTile } from './ScreenPinTile';
|
||||
|
||||
const MAX_SCREENS_AND_PINS = 3;
|
||||
|
||||
export const ScreensAndPins = ({ items }) => {
|
||||
const { showNames } = useCallState();
|
||||
const { pinnedId, sidebarView } = useUIState();
|
||||
const viewRef = useRef(null);
|
||||
const [dimensions, setDimensions] = useState({
|
||||
width: 1,
|
||||
height: 1,
|
||||
});
|
||||
|
||||
useResize(() => {
|
||||
const { width, height } = viewRef.current?.getBoundingClientRect();
|
||||
setDimensions({
|
||||
width,
|
||||
height,
|
||||
});
|
||||
}, [viewRef, sidebarView]);
|
||||
|
||||
const visibleItems = useDeepCompareMemo(() => {
|
||||
const isPinnedScreenshare = ({ id, isScreenshare }) =>
|
||||
isScreenshare && id === pinnedId;
|
||||
if (items.some(isPinnedScreenshare)) {
|
||||
return items.filter(isPinnedScreenshare);
|
||||
}
|
||||
return items;
|
||||
}, [items, pinnedId]);
|
||||
|
||||
const { height, maxWidth, aspectRatio } = useMemo(() => {
|
||||
/**
|
||||
* We're relying on calculating what there is room for
|
||||
* for the total number of s+p tiles instead of using
|
||||
* videoTrack.getSettings because (currently) getSettings
|
||||
* is unreliable in Firefox.
|
||||
*/
|
||||
const containerAR = dimensions.width / dimensions.height;
|
||||
const maxItems = Math.min(visibleItems.length, MAX_SCREENS_AND_PINS);
|
||||
const cols = Math.min(maxItems, Math.ceil(containerAR));
|
||||
const rows = Math.ceil(visibleItems.length / cols);
|
||||
const height = dimensions.height / rows;
|
||||
const maxWidth = dimensions.width / cols;
|
||||
return {
|
||||
height,
|
||||
maxWidth,
|
||||
aspectRatio: maxWidth / height,
|
||||
};
|
||||
}, [dimensions, visibleItems?.length]);
|
||||
|
||||
return (
|
||||
<div ref={viewRef}>
|
||||
{visibleItems.map((item) => (
|
||||
<div
|
||||
className="tileWrapper"
|
||||
key={item.id}
|
||||
style={{
|
||||
height,
|
||||
maxWidth,
|
||||
}}
|
||||
>
|
||||
<ScreenPinTile
|
||||
height={height}
|
||||
hideName={!showNames}
|
||||
item={item}
|
||||
maxWidth={maxWidth}
|
||||
ratio={aspectRatio}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
<style jsx>{`
|
||||
div {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
div :global(.tileWrapper) {
|
||||
background: var(--background);
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex: none;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
div :global(.tile .content) {
|
||||
margin: auto;
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ScreensAndPins;
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { ScreensAndPins } from './ScreensAndPins';
|
||||
|
|
@ -18,10 +18,7 @@ export const SpeakerTile = ({ participant, screenRef }) => {
|
|||
setScreenHeight(rect.height);
|
||||
}, [screenRef]);
|
||||
|
||||
useResize(() => {
|
||||
updateRatio();
|
||||
}, [updateRatio]);
|
||||
|
||||
useResize(() => updateRatio(), [updateRatio]);
|
||||
useEffect(() => updateRatio(), [updateRatio]);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
import React, { useEffect, useMemo, useRef } from 'react';
|
||||
import { Container } from '@custom/basic-call/components/Call/Container';
|
||||
import Header from '@custom/basic-call/components/Call/Header';
|
||||
import ParticipantBar from '@custom/shared/components/ParticipantBar/ParticipantBar';
|
||||
import VideoContainer from '@custom/shared/components/VideoContainer/VideoContainer';
|
||||
import { useCallState } from '@custom/shared/contexts/CallProvider';
|
||||
import { useParticipants } from '@custom/shared/contexts/ParticipantsProvider';
|
||||
import { useTracks } from '@custom/shared/contexts/TracksProvider';
|
||||
import { useUIState } from '@custom/shared/contexts/UIStateProvider';
|
||||
import { isScreenId } from '@custom/shared/contexts/participantsState';
|
||||
import { ScreensAndPins } from './ScreensAndPins';
|
||||
import { SpeakerTile } from './SpeakerTile';
|
||||
|
||||
const SIDEBAR_WIDTH = 186;
|
||||
|
|
@ -40,10 +38,10 @@ export const SpeakerView = () => {
|
|||
return participants.length > 1 || hasScreenshares;
|
||||
}, [participants, pinnedId, screens]);
|
||||
|
||||
/* const screenShareTiles = useMemo(
|
||||
const screenShareTiles = useMemo(
|
||||
() => <ScreensAndPins items={screensAndPinned} />,
|
||||
[screensAndPinned]
|
||||
); */
|
||||
);
|
||||
|
||||
const hasScreenshares = useMemo(() => screens.length > 0, [screens]);
|
||||
|
||||
|
|
@ -80,7 +78,11 @@ export const SpeakerView = () => {
|
|||
return (
|
||||
<div className="speaker-view">
|
||||
<div ref={activeRef} className="active">
|
||||
<SpeakerTile participant={currentSpeaker} screenRef={activeRef} />
|
||||
{screensAndPinned.length > 0 ? (
|
||||
screenShareTiles
|
||||
) : (
|
||||
<SpeakerTile screenRef={activeRef} participant={currentSpeaker} />
|
||||
)}
|
||||
</div>
|
||||
{showSidebar && (
|
||||
<ParticipantBar
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ export const ViewTray = () => {
|
|||
const { participants } = useParticipants();
|
||||
const { viewMode, setPreferredViewMode } = useUIState();
|
||||
|
||||
const onClick = () =>
|
||||
setPreferredViewMode(viewMode === VIEW_MODE_SPEAKER ? VIEW_MODE_GRID: VIEW_MODE_SPEAKER);
|
||||
const onViewClick = () =>
|
||||
setPreferredViewMode(viewMode === VIEW_MODE_SPEAKER ? VIEW_MODE_GRID : VIEW_MODE_SPEAKER);
|
||||
|
||||
return (
|
||||
<TrayButton
|
||||
label={viewMode === VIEW_MODE_GRID ? 'Speaker': 'Grid'}
|
||||
disabled={participants.length < 2}
|
||||
onClick={onClick}
|
||||
onClick={onViewClick}
|
||||
>
|
||||
{viewMode === VIEW_MODE_SPEAKER ? <IconGridView />: <IconSpeakerView />}
|
||||
</TrayButton>
|
||||
|
|
|
|||
Loading…
Reference in New Issue