Skip to content

Commit

Permalink
Try different layouts
Browse files Browse the repository at this point in the history
  • Loading branch information
jamsea committed Jul 31, 2024
1 parent a3e8ebd commit fcd0847
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 132 deletions.
243 changes: 152 additions & 91 deletions compositions/daily-baseline/components/VideoGrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { useGrid, useParams } from "#vcs-react/hooks";
import * as layoutFuncs from "../layouts.js";
import { PausedPlaceholder } from "./PausedPlaceholder.js";
import decorateVideoGridItem from "./overrides/decorateVideoGridItem.js";
import { DEFAULT_OFFSET_VIDEO_SINGLE_PX } from "../constants.js";
import {
DEFAULT_OFFSET_VIDEO_SINGLE_PX,
PositionCorner,
} from "../constants.js";

let primaryColor;
let pauseBgColor;
Expand All @@ -16,19 +19,45 @@ export default function AugmentedGrid(props) {
const currentLayout = params["currentLayout"];
primaryColor = params["voedaily.primary.color"];
pauseBgColor = params["voedaily.pause.bgColor"];
let baseVideo, otherOverlays;

let baseVideo, pipOverlay, otherOverlays;
let pipIdx;
let bubbleIdx;

switch (currentLayout) {
case "2x2":
pipIdx = null;
bubbleIdx = 4;
baseVideo = <VideoGrid {...props} />;
baseVideo = (
<VideoGrid
participantDescs={participantDescs.slice(0, 4)}
itemInterval_gu={0}
outerPadding_gu={0}
/>
);
break;
case "2x2withPIP":
pipIdx = 4;
bubbleIdx = 5;
baseVideo = (
<VideoGrid
participantDescs={participantDescs.slice(0, 4)}
itemInterval_gu={0}
outerPadding_gu={0}
/>
);
break;
default:
pipIdx = null;
bubbleIdx = null;
baseVideo = <VideoGrid {...props} />;
break;
}
if (pipIdx) {
if (participantDescs.length > pipIdx) {
pipOverlay = <SimplePip participant={participantDescs[pipIdx]} />;
}
}
if (bubbleIdx) {
if (participantDescs.length > bubbleIdx) {
otherOverlays = (
Expand All @@ -40,6 +69,7 @@ export default function AugmentedGrid(props) {
return (
<Box>
{baseVideo && baseVideo}
{pipOverlay && pipOverlay}
{otherOverlays && otherOverlays}
</Box>
);
Expand All @@ -62,11 +92,99 @@ function getInitials(name) {
}
return initials;
}

// a simple picture-in-picture with hardcoded settings
// using the same layout function as VideoPip.js
//
function SimplePip({ participant }) {
const { videoId, displayName = "", paused } = participant;
const pxPerGu = useGrid().pixelsPerGridUnit;
const pipSize_gu = 6;

const layoutProps = {
positionCorner: PositionCorner.TOP_RIGHT,
aspectRatio: 1,
height_gu: pipSize_gu,
margin_gu: 2,
};
const layout = [layoutFuncs.pip, layoutProps];

const labelStyle = {
textColor: primaryColor,
fontFamily: "DMSans",
fontWeight: "700",
textAlign: "center",
fontSize_gu: 2,
};

const videoStyle = {
cornerRadius_px: (pipSize_gu / 2) * pxPerGu, // mask to circle
};
const outlineStyle = {
...videoStyle,
strokeWidth_px: pxPerGu / 3, // the outline for the video
strokeColor: primaryColor,
};
const fillStyle = {
...videoStyle,
fillColor: pauseBgColor,
strokeWidth_px: pxPerGu / 3, // the outline for the video
strokeColor: primaryColor,
};

let content;
if (paused || videoId == null) {
// no video available, show a placeholder with the icon
content = (
<Box style={fillStyle} layout={layout}>
{displayName ? (
<Text
clip
style={labelStyle}
layout={[
layoutFuncs.placeText,
{ vAlign: "center", hAlign: "center", yOffset_gu: 0.45 },
]}
>
{getInitials(displayName)}
</Text>
) : (
<Image src="user_white_64.png" scaleMode="fill" />
)}
</Box>
);
} else {
content = (
<Box style={outlineStyle} layout={layout}>
<Video
id="pipVideo"
src={videoId}
scaleMode="fill"
style={videoStyle}
/>
</Box>
);
}

const arr = [content];

return (
<Box
clip
style={{
cornerRadius_px: videoStyle.cornerRadius_px,
}}
>
{arr}
</Box>
);
}

// a row of picture-in-picture videos, using an inline layout function
//
function PipRow({ participantDescs }) {
const pxPerGu = useGrid().pixelsPerGridUnit;
const pipSize_gu = 6;
const pipSize_gu = 4;
const margin_gu = 2;
const interval_gu = 1;

Expand Down Expand Up @@ -104,27 +222,29 @@ function PipRow({ participantDescs }) {
fontFamily: "DMSans",
fontWeight: "700",
textAlign: "center",
fontSize_px: 40,
fontSize_gu: 2,
};

return participantDescs.map((pd, idx) => {
const { videoId, paused, displayName = "" } = pd;

return paused ? (
<Box id="pipOutline" style={fillStyle} layout={[rowLayoutFn, { idx }]}>
<Box
id={idx + "_pipAudience"}
style={fillStyle}
layout={[rowLayoutFn, { idx }]}
>
{displayName ? (
<Box clip layout={[layoutFuncs.centerYIfNeeded, { minH_gu: 2 }]}>
<Text
clip
style={labelStyle}
layout={[
layoutFuncs.placeText,
{ vAlign: "center", hAlign: "center", idx },
]}
>
{getInitials(displayName)}
</Text>
</Box>
<Text
clip
style={labelStyle}
layout={[
layoutFuncs.placeText,
{ vAlign: "center", hAlign: "center", yOffset_gu: 0.45 },
]}
>
{getInitials(displayName)}
</Text>
) : (
<Image src="user_white_64.png" scaleMode="fill" />
)}
Expand All @@ -139,35 +259,20 @@ function PipRow({ participantDescs }) {

function VideoGrid(gridProps) {
let {
showLabels,
scaleMode,
scaleModeForScreenshare,
videoStyle,
videoLabelStyle,
placeholderStyle,
labelsOffset_px = 0,
participantDescs,
highlightDominant = true,
itemInterval_gu = -1,
outerPadding_gu = -1,
preserveItemAspectRatio = true,
fullScreenHighlightItemIndex = -1,
} = gridProps;

const totalNumItems = 4; // participantDescs.length;
const take4Parts = participantDescs.slice(0, 4);
const totalNumItems = participantDescs.length;
itemInterval_gu = Math.max(-1, itemInterval_gu);
outerPadding_gu = Math.max(-1, outerPadding_gu);

function makeItem(index, itemProps) {
const {
isAudioOnly,
isScreenshare,
videoId,
displayName,
highlighted,
paused,
} = itemProps;
const { isAudioOnly, videoId, displayName, paused } = itemProps;
let key = "videogriditem_" + index;

let itemLayout;
Expand Down Expand Up @@ -196,14 +301,17 @@ function VideoGrid(gridProps) {
// override point for custom decorations on grid items
const {
enableDefaultLabels = true,
enableDefaultHighlight = true,
customComponent: customDecoratorComponent,
clipItem = false,
customLayoutForVideo,
} = decorateVideoGridItem(index, itemProps, gridProps);

const fillStyle = {
fillColor: pauseBgColor,
};

let participantLabel;
if (enableDefaultLabels && showLabels && displayName.length > 0) {
if (enableDefaultLabels && displayName.length > 0) {
// for a single participant, put the label inside the video frame like in VideoSingle.
// the 10px offsets applied here for single mode are the same as VideoSingle.
const isGrid = totalNumItems > 1;
Expand All @@ -218,95 +326,48 @@ function VideoGrid(gridProps) {
participantLabel = (
<Text
key={"label_" + displayName}
style={videoLabelStyle}
layout={[
labelLayout,
{ textH: videoLabelStyle.fontSize_px, offsets },
]}
layout={[labelLayout, { textH: 40, offsets }]}
clip
>
{displayName}
</Text>
);
}

const videoScaleMode = isScreenshare ? scaleModeForScreenshare : scaleMode;
const videoScaleMode = "fit";
const hasLiveVideo = !isAudioOnly && !paused;

let highlight;
if (enableDefaultHighlight && highlightDominant && highlighted) {
const highlightStyle = {
strokeColor: videoStyle.highlightColor,
strokeWidth_px: videoStyle.highlightStrokeWidth_px,
cornerRadius_px: videoStyle.cornerRadius_px,
};

let highlightLayout;
if (hasLiveVideo && videoScaleMode === "fit") {
const { frameSize } = itemProps;
const aspectRatio =
frameSize?.w > 0 && frameSize?.h > 0 ? frameSize.w / frameSize.h : 0;
if (aspectRatio > 0) {
highlightLayout = [
layoutFuncs.fit,
{
contentAspectRatio: aspectRatio,
},
];
}
}
highlight = (
<Box
style={highlightStyle}
key={key + "_highlight"}
layout={highlightLayout}
/>
);
}

let video;
if (!hasLiveVideo) {
video = (
<PausedPlaceholder
layout={customLayoutForVideo}
{...{ placeholderStyle }}
placeholderStyle={fillStyle}
/>
);
} else {
video = (
<Video
src={videoId}
style={videoStyle}
scaleMode={videoScaleMode}
layout={customLayoutForVideo}
blend={videoBlend}
/>
);
}

const containerStyle = clipItem
? {
cornerRadius_px: videoStyle.cornerRadius_px,
}
: null;

return (
<Box
key={key}
id={key}
layout={itemLayout}
style={containerStyle}
clip={clipItem}
>
<Box key={key} id={key} layout={itemLayout} clip={clipItem}>
{video}
{participantLabel}
{highlight}
{customDecoratorComponent}
</Box>
);
}

return (
<Box id="videogrid">{take4Parts.map((d, idx) => makeItem(idx, d))}</Box>
<Box id="videogrid">
{participantDescs.map((d, idx) => makeItem(idx, d))}
</Box>
);
}
Loading

0 comments on commit fcd0847

Please sign in to comment.