Update the grid layout whenever someone screenshares (uses participant bar)

This commit is contained in:
harshithpabbati 2021-12-30 14:00:52 +05:30
parent 209b9bd72e
commit 22b4afbb34
4 changed files with 113 additions and 21 deletions

View File

@ -1,13 +1,54 @@
import React from 'react';
import React, { useMemo } from 'react';
import ExpiryTimer from '@custom/shared/components/ExpiryTimer';
import { useCallState } from '@custom/shared/contexts/CallProvider';
import { useCallUI } from '@custom/shared/hooks/useCallUI';
import PropTypes from 'prop-types';
import App from '@custom/basic-call/components/App';
import { ChatProvider } from '../../contexts/ChatProvider';
import Room from '../Call/Room';
import { Asides } from './Asides';
import { Modals } from './Modals';
// Extend our basic call app component with the chat context
export const CustomApp = () => (
<ChatProvider>
<App />
</ChatProvider>
);
export const App = ({ customComponentForState }) => {
const { roomExp, state } = useCallState();
export default CustomApp;
const componentForState = useCallUI({
state,
room: <Room />,
...customComponentForState,
});
// Memoize children to avoid unnecassary renders from HOC
return useMemo(
() => (
<>
<ChatProvider>
{roomExp && <ExpiryTimer expiry={roomExp} />}
<div className="app">
{componentForState()}
<Modals />
<Asides />
<style jsx>{`
color: white;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
.loader {
margin: 0 auto;
}
`}</style>
</div>
</ChatProvider>
</>
),
[componentForState, roomExp]
);
};
App.propTypes = {
customComponentForState: PropTypes.any,
};
export default App;

View File

@ -1,9 +1,13 @@
import React, { useState, useMemo, useEffect, useRef } from 'react';
import ParticipantBar from '@custom/shared/components/ParticipantBar';
import Tile from '@custom/shared/components/Tile';
import { DEFAULT_ASPECT_RATIO } from '@custom/shared/constants';
import { useCallState } from '@custom/shared/contexts/CallProvider';
import { useParticipants } from '@custom/shared/contexts/ParticipantsProvider';
import { useDeepCompareMemo } from 'use-deep-compare';
const SIDEBAR_WIDTH = 186;
/**
* Basic unpaginated video tile grid, scaled by aspect ratio
*
@ -18,7 +22,8 @@ import { useDeepCompareMemo } from 'use-deep-compare';
export const VideoGrid = React.memo(
() => {
const containerRef = useRef();
const { allParticipants } = useParticipants();
const { allParticipants, participants, screens, localParticipant } = useParticipants();
const { showLocalVideo } = useCallState();
const [dimensions, setDimensions] = useState({
width: 1,
height: 1,
@ -45,10 +50,12 @@ export const VideoGrid = React.memo(
};
}, []);
const hasScreenshares = useMemo(() => screens.length > 0, [screens]);
// Basic brute-force packing algo
const layout = useMemo(() => {
const aspectRatio = DEFAULT_ASPECT_RATIO;
const tileCount = allParticipants.length || 0;
const tileCount = hasScreenshares ? screens.length : participants.length || 0;
const w = dimensions.width;
const h = dimensions.height;
@ -87,29 +94,73 @@ export const VideoGrid = React.memo(
}
return bestLayout;
}, [dimensions, allParticipants]);
}, [hasScreenshares, screens.length, participants.length, dimensions.width, dimensions.height]);
const otherParticipants = useMemo(
() => participants.filter(({ isLocal }) => !isLocal),
[participants]
);
const fixedItems = useMemo(() => {
const items = [];
if (showLocalVideo) {
items.push(localParticipant);
}
if (hasScreenshares && otherParticipants.length > 0) {
items.push(otherParticipants[0]);
}
return items;
}, [hasScreenshares, localParticipant, otherParticipants, showLocalVideo]);
const otherItems = useMemo(() => {
if (otherParticipants.length > 1) {
return otherParticipants.slice(hasScreenshares ? 1 : 0);
}
return [];
}, [hasScreenshares, otherParticipants]);
// Memoize our tile list to avoid unnecassary re-renders
const tiles = useDeepCompareMemo(
() =>
allParticipants.map((p) => (
participants.map((p) => (
<Tile
participant={p}
key={p.id}
mirrored={!p.isScreenshare}
mirrored
style={{ maxWidth: layout.width, maxHeight: layout.height }}
/>
)),
[layout, allParticipants]
[layout, participants]
);
if (!allParticipants.length) {
return null;
}
const screenShareTiles = useDeepCompareMemo(
() =>
screens.map((p) => (
<Tile
participant={p}
key={p.id}
mirrored={false}
style={{ maxWidth: layout.width, maxHeight: layout.height }}
/>
)),
[layout, screens]
);
if (!participants.length) return null;
return (
<div className="video-grid" ref={containerRef}>
<div className="tiles">{tiles}</div>
<div className="tiles">
{screenShareTiles}
{!hasScreenshares && tiles}
</div>
{hasScreenshares && (
<ParticipantBar
fixed={fixedItems}
others={otherItems}
width={SIDEBAR_WIDTH}
/>
)}
<style jsx>{`
.video-grid {
align-items: center;

View File

@ -2,7 +2,7 @@ import React from 'react';
import GlobalStyle from '@custom/shared/components/GlobalStyle';
import Head from 'next/head';
import PropTypes from 'prop-types';
import { CustomApp } from '../components/App/App';
import { App as CustomApp } from '../components/App/App';
import ChatAside from '../components/Call/ChatAside';
import Tray from '../components/Tray';

View File

@ -5,7 +5,7 @@ import React, {
useRef,
useState,
} from 'react';
import { Tile } from '@custom/shared/components/Tile';
import Tile from '@custom/shared/components/Tile';
import { DEFAULT_ASPECT_RATIO } from '@custom/shared/constants';
import { useCallState } from '@custom/shared/contexts/CallProvider';
import { useParticipants } from '@custom/shared/contexts/ParticipantsProvider';