From 9e367db32413840a4a6bd936021e5eedef6b70e4 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Wed, 14 Sep 2022 19:05:05 -0400 Subject: [PATCH 1/3] Maximise the active speaker when the window is small --- src/room/InCallView.module.css | 14 +++-- src/room/InCallView.tsx | 78 +++++++++++++++++---------- src/video-grid/VideoGrid.stories.tsx | 1 + src/video-grid/VideoTile.module.css | 2 +- src/video-grid/VideoTile.tsx | 33 ++++++------ src/video-grid/VideoTileContainer.tsx | 10 ++-- 6 files changed, 86 insertions(+), 52 deletions(-) diff --git a/src/room/InCallView.module.css b/src/room/InCallView.module.css index f8783bf..8c37d46 100644 --- a/src/room/InCallView.module.css +++ b/src/room/InCallView.module.css @@ -43,7 +43,7 @@ limitations under the License. display: flex; justify-content: center; align-items: center; - height: 64px; + height: calc(50px + 2 * 8px); } .footer > * { @@ -54,7 +54,7 @@ limitations under the License. margin-right: 0px; } -.footerFullscreen { +.maximised .footer { position: absolute; width: 100%; bottom: 0; @@ -67,8 +67,14 @@ limitations under the License. transform: translate(-50%, -50%); } -@media (min-width: 800px) { +@media (min-height: 300px) { .footer { - height: 118px; + height: calc(50px + 2 * 24px); + } +} + +@media (min-width: 800px) { + .footer { + height: calc(50px + 2 * 32px); } } diff --git a/src/room/InCallView.tsx b/src/room/InCallView.tsx index 647136e..2460825 100644 --- a/src/room/InCallView.tsx +++ b/src/room/InCallView.tsx @@ -16,6 +16,8 @@ limitations under the License. import React, { useEffect, useCallback, useMemo, useRef } from "react"; import { usePreventScroll } from "@react-aria/overlays"; +import useMeasure from "react-use-measure"; +import { ResizeObserver } from "@juggle/resize-observer"; import { MatrixClient } from "matrix-js-sdk/src/client"; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { GroupCall } from "matrix-js-sdk/src/webrtc/groupCall"; @@ -111,9 +113,20 @@ export function InCallView({ hideHeader, }: Props) { usePreventScroll(); - const elementRef = useRef(); + const containerRef1 = useRef(null); + const [containerRef2, bounds] = useMeasure({ polyfill: ResizeObserver }); + // Merge the refs so they can attach to the same element + const containerRef = useCallback( + (el: HTMLDivElement) => { + containerRef1.current = el; + containerRef2(el); + }, + [containerRef1, containerRef2] + ); + const { layout, setLayout } = useVideoGridLayout(screenshareFeeds.length > 0); - const { toggleFullscreen, fullscreenParticipant } = useFullscreen(elementRef); + const { toggleFullscreen, fullscreenParticipant } = + useFullscreen(containerRef1); const [spatialAudio] = useSpatialAudio(); @@ -170,9 +183,7 @@ export function InCallView({ id: callFeed.stream.id, callFeed, focused: - screenshareFeeds.length === 0 && layout === "spotlight" - ? callFeed.userId === activeSpeaker - : false, + screenshareFeeds.length === 0 && callFeed.userId === activeSpeaker, isLocal: callFeed.isLocal(), presenter: false, }); @@ -197,7 +208,20 @@ export function InCallView({ } return participants; - }, [userMediaFeeds, activeSpeaker, screenshareFeeds, layout]); + }, [userMediaFeeds, activeSpeaker, screenshareFeeds]); + + // The maximised participant: either the participant that the user has + // manually put in fullscreen, or the focused (active) participant if the + // window is too small to show everyone + const maximisedParticipant = useMemo( + () => + fullscreenParticipant ?? bounds.height <= 500 + ? items.find((item) => item.focused) ?? + items.find((item) => item.callFeed) ?? + null + : null, + [fullscreenParticipant, bounds, items] + ); const renderAvatar = useCallback( (roomMember: RoomMember, width: number, height: number) => { @@ -217,7 +241,7 @@ export function InCallView({ [] ); - const renderContent = useCallback((): JSX.Element => { + const renderContent = (): JSX.Element => { if (items.length === 0) { return (
@@ -225,16 +249,19 @@ export function InCallView({
); } - if (fullscreenParticipant) { + if (maximisedParticipant) { return ( ); @@ -250,43 +277,36 @@ export function InCallView({ audioContext={audioContext} audioDestination={audioDestination} disableSpeakingIndicator={items.length < 3} - isFullscreen={!!fullscreenParticipant} + maximised={false} + fullscreen={false} onFullscreen={toggleFullscreen} {...rest} /> )} ); - }, [ - fullscreenParticipant, - items, - audioContext, - audioDestination, - layout, - renderAvatar, - toggleFullscreen, - ]); + }; const { modalState: rageshakeRequestModalState, modalProps: rageshakeRequestModalProps, } = useRageshakeRequestModal(groupCall.room.roomId); - const footerClassNames = classNames(styles.footer, { - [styles.footerFullscreen]: fullscreenParticipant, + const containerClasses = classNames(styles.inRoom, { + [styles.maximised]: maximisedParticipant, }); return ( -
+