diff --git a/src/room/InCallView.tsx b/src/room/InCallView.tsx index 581502fc..dd2a0e75 100644 --- a/src/room/InCallView.tsx +++ b/src/room/InCallView.tsx @@ -35,7 +35,7 @@ import { import useMeasure from "react-use-measure"; import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import classNames from "classnames"; -import { BehaviorSubject } from "rxjs"; +import { BehaviorSubject, of } from "rxjs"; import { useObservableEagerState } from "observable-hooks"; import LogoMark from "../icons/LogoMark.svg?react"; @@ -298,6 +298,13 @@ export const InCallView: FC = ({ const onToggleExpanded = useObservableEagerState( vm.toggleSpotlightExpanded, ); + const showVideo = useObservableEagerState( + useMemo( + () => + model.type === "grid" ? vm.showGridVideo(model.vm) : of(true), + [model], + ), + ); const showSpeakingIndicatorsValue = useObservableEagerState( vm.showSpeakingIndicators, ); @@ -314,6 +321,7 @@ export const InCallView: FC = ({ targetHeight={targetHeight} className={classNames(className, styles.tile)} style={style} + showVideo={showVideo} showSpeakingIndicators={showSpeakingIndicatorsValue} /> ) : ( diff --git a/src/state/CallViewModel.ts b/src/state/CallViewModel.ts index d5a551e0..43c77b2d 100644 --- a/src/state/CallViewModel.ts +++ b/src/state/CallViewModel.ts @@ -694,8 +694,27 @@ export class CallViewModel extends ViewModel { shareReplay(1), ); + /** + * Determines whether video should be shown for a certain piece of media + * appearing in the grid. + */ + public showGridVideo(vm: MediaViewModel): Observable { + return this.layout.pipe( + map( + (l) => + !( + (l.type === "spotlight-landscape" || + l.type === "spotlight-portrait") && + // This media is already visible in the spotlight; avoid duplication + l.spotlight.some((spotlightVm) => spotlightVm === vm) + ), + ), + distinctUntilChanged(), + ); + } + public showSpeakingIndicators: Observable = this.layout.pipe( - map((l) => l.type !== "one-on-one" && l.type !== "spotlight-expanded"), + map((l) => l.type !== "one-on-one" && !l.type.startsWith("spotlight-")), distinctUntilChanged(), shareReplay(1), ); diff --git a/src/tile/GridTile.tsx b/src/tile/GridTile.tsx index f1e0c72b..01e0f420 100644 --- a/src/tile/GridTile.tsx +++ b/src/tile/GridTile.tsx @@ -60,6 +60,7 @@ interface TileProps { targetWidth: number; targetHeight: number; displayName: string; + showVideo: boolean; showSpeakingIndicators: boolean; } @@ -74,6 +75,7 @@ const UserMediaTile = forwardRef( ( { vm, + showVideo, showSpeakingIndicators, menuStart, menuEnd, @@ -120,7 +122,7 @@ const UserMediaTile = forwardRef( video={video} member={vm.member} unencryptedWarning={unencryptedWarning} - videoEnabled={videoEnabled} + videoEnabled={videoEnabled && showVideo} videoFit={cropVideo ? "cover" : "contain"} className={classNames(className, styles.tile, { [styles.speaking]: showSpeakingIndicators && speaking, @@ -279,6 +281,7 @@ interface GridTileProps { targetHeight: number; className?: string; style?: ComponentProps["style"]; + showVideo: boolean; showSpeakingIndicators: boolean; }