mirror of
https://github.com/vector-im/element-call.git
synced 2026-08-29 21:15:19 +00:00
WIP
This commit is contained in:
@@ -42,6 +42,7 @@ import {
|
||||
ScreenshareButton,
|
||||
SettingsButton,
|
||||
InviteButton,
|
||||
SimulateJoinButton,
|
||||
} from "../button";
|
||||
import {
|
||||
Header,
|
||||
@@ -58,6 +59,7 @@ import {
|
||||
import {
|
||||
useShowInspector,
|
||||
useShowConnectionStats,
|
||||
useVideoGridSandboxMode,
|
||||
} from "../settings/useSetting";
|
||||
import { useModalTriggerState } from "../Modal";
|
||||
import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
|
||||
@@ -83,6 +85,8 @@ import { useFullscreen } from "./useFullscreen";
|
||||
import { useLayoutStates } from "../video-grid/Layout";
|
||||
import { useSFUConfig } from "../livekit/OpenIDLoader";
|
||||
import { E2EELock } from "../E2EELock";
|
||||
import { useFakeTiles } from "./useFakeTiles";
|
||||
import { FakeItemData, FakeVideoTile } from "../video-grid/FakeVideoTile";
|
||||
|
||||
const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {});
|
||||
// There is currently a bug in Safari our our code with cloning and sending MediaStreams
|
||||
@@ -160,6 +164,9 @@ export function InCallView({
|
||||
|
||||
const [showInspector] = useShowInspector();
|
||||
const [showConnectionStats] = useShowConnectionStats();
|
||||
const [videoGridSandboxMode] = useVideoGridSandboxMode()
|
||||
|
||||
const { fakeTiles: fakeItems, simulateJoin } = useFakeTiles()
|
||||
|
||||
const { hideScreensharing } = useUrlParams();
|
||||
|
||||
@@ -227,9 +234,11 @@ export function InCallView({
|
||||
const reducedControls = boundsValid && bounds.width <= 400;
|
||||
const noControls = reducedControls && bounds.height <= 400;
|
||||
|
||||
const items = useParticipantTiles(livekitRoom, participants);
|
||||
const realItems = useParticipantTiles(livekitRoom, participants);
|
||||
const { fullscreenItem, toggleFullscreen, exitFullscreen } =
|
||||
useFullscreen(items);
|
||||
useFullscreen(realItems);
|
||||
|
||||
const items = useMemo<TileDescriptor<ItemData | FakeItemData>[]>(() => videoGridSandboxMode ? [...realItems, ...fakeItems] : realItems, [videoGridSandboxMode, realItems, fakeItems])
|
||||
|
||||
// The maximised participant: either the participant that the user has
|
||||
// manually put in fullscreen, or the focused (active) participant if the
|
||||
@@ -238,9 +247,9 @@ export function InCallView({
|
||||
() =>
|
||||
fullscreenItem ??
|
||||
(noControls
|
||||
? items.find((item) => item.isSpeaker) ?? items.at(0) ?? null
|
||||
? realItems.find((item) => item.isSpeaker) ?? realItems.at(0) ?? null
|
||||
: null),
|
||||
[fullscreenItem, noControls, items]
|
||||
[fullscreenItem, noControls, realItems]
|
||||
);
|
||||
|
||||
const Grid =
|
||||
@@ -283,16 +292,19 @@ export function InCallView({
|
||||
disableAnimations={prefersReducedMotion || isSafari}
|
||||
layoutStates={layoutStates}
|
||||
>
|
||||
{(props) => (
|
||||
{(props) => props.data.type === "real" ? (
|
||||
<VideoTile
|
||||
maximised={false}
|
||||
fullscreen={false}
|
||||
onToggleFullscreen={toggleFullscreen}
|
||||
showSpeakingIndicator={items.length > 2}
|
||||
showSpeakingIndicator={realItems.length > 2}
|
||||
showConnectionStats={showConnectionStats}
|
||||
{...props}
|
||||
data={props.data}
|
||||
ref={props.ref as Ref<HTMLDivElement>}
|
||||
/>
|
||||
) : (
|
||||
<FakeVideoTile {...props} data={props.data} />
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
@@ -381,6 +393,8 @@ export function InCallView({
|
||||
);
|
||||
}
|
||||
buttons.push(<SettingsButton key="4" onPress={openSettings} />);
|
||||
if (videoGridSandboxMode)
|
||||
buttons.push(<SimulateJoinButton key="5" onPress={simulateJoin} />)
|
||||
}
|
||||
|
||||
buttons.push(
|
||||
@@ -480,7 +494,7 @@ function useParticipantTiles(
|
||||
const member = matrixParticipants.get(id);
|
||||
allGhosts &&= member === undefined;
|
||||
|
||||
const userMediaTile = {
|
||||
const userMediaTile: TileDescriptor<ItemData> = {
|
||||
id,
|
||||
focused: false,
|
||||
isPresenter: sfuParticipant.isScreenShareEnabled,
|
||||
@@ -491,6 +505,7 @@ function useParticipantTiles(
|
||||
local: sfuParticipant.isLocal,
|
||||
largeBaseSize: false,
|
||||
data: {
|
||||
type: "real",
|
||||
id,
|
||||
member,
|
||||
sfuParticipant,
|
||||
|
||||
96
src/room/useFakeTiles.ts
Normal file
96
src/room/useFakeTiles.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright 2023 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { TileDescriptor } from '../video-grid/VideoGrid'
|
||||
import { FakeItemData } from '../video-grid/FakeVideoTile'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useLatest } from '../useLatest'
|
||||
import { generateRandomName } from '../auth/generateRandomName'
|
||||
|
||||
interface FakeTiles {
|
||||
fakeTiles: TileDescriptor<FakeItemData>[]
|
||||
simulateJoin: () => void
|
||||
}
|
||||
|
||||
export const useFakeTiles = (): FakeTiles => {
|
||||
const [tiles, setTiles] = useState<TileDescriptor<FakeItemData>[]>([])
|
||||
const latestSetTiles = useLatest(setTiles)
|
||||
|
||||
const simulateJoin = useCallback(() => {
|
||||
const name = generateRandomName()
|
||||
const newTile: TileDescriptor<FakeItemData> = {
|
||||
id: name,
|
||||
focused: false,
|
||||
isPresenter: false,
|
||||
isSpeaker: false,
|
||||
hasVideo: false,
|
||||
local: false,
|
||||
largeBaseSize: false,
|
||||
data: {
|
||||
type: "fake",
|
||||
name,
|
||||
screenshare: false,
|
||||
speaking: false,
|
||||
simulateScreenshare: () => latestSetTiles.current(ts => {
|
||||
if (ts.some(t => t.data.name === newTile.id && t.data.screenshare)) {
|
||||
// No-op since they're already screensharing
|
||||
return ts
|
||||
} else {
|
||||
const newScreenshareTile: TileDescriptor<FakeItemData> = {
|
||||
id: `${name}:screenshare`,
|
||||
focused: false,
|
||||
isPresenter: false,
|
||||
isSpeaker: false,
|
||||
hasVideo: true,
|
||||
local: false,
|
||||
largeBaseSize: true,
|
||||
placeNear: newTile.id,
|
||||
data: {
|
||||
type: "fake",
|
||||
name,
|
||||
screenshare: true,
|
||||
speaking: false,
|
||||
remove: () => latestSetTiles.current(ts => ts.filter(t => t.id !== newScreenshareTile.id))
|
||||
}
|
||||
}
|
||||
return [...ts, newScreenshareTile]
|
||||
}
|
||||
}),
|
||||
simulateSpeaking: () => latestSetTiles.current(ts => ts.map(t => {
|
||||
if (t.id === newTile.id) {
|
||||
return {
|
||||
...t,
|
||||
isSpeaker: !t.isSpeaker,
|
||||
data: {
|
||||
...t.data,
|
||||
speaking: !t.isSpeaker,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return t
|
||||
}
|
||||
})),
|
||||
remove: () => latestSetTiles.current(ts => ts.filter(t => t.id !== newTile.id))
|
||||
}
|
||||
}
|
||||
setTiles(ts => [...ts, newTile])
|
||||
}, [setTiles, latestSetTiles])
|
||||
|
||||
return {
|
||||
fakeTiles: tiles,
|
||||
simulateJoin,
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,12 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { useCallback, useLayoutEffect, useRef } from "react";
|
||||
import { useCallback, useLayoutEffect } from "react";
|
||||
|
||||
import { TileDescriptor } from "../video-grid/VideoGrid";
|
||||
import { useReactiveState } from "../useReactiveState";
|
||||
import { useEventTarget } from "../useEvents";
|
||||
import { useLatest } from "../useLatest";
|
||||
|
||||
const isFullscreen = () =>
|
||||
Boolean(document.fullscreenElement) ||
|
||||
@@ -69,11 +70,8 @@ export function useFullscreen<T>(items: TileDescriptor<T>[]): {
|
||||
[items]
|
||||
);
|
||||
|
||||
const latestItems = useRef<TileDescriptor<T>[]>(items);
|
||||
latestItems.current = items;
|
||||
|
||||
const latestFullscreenItem = useRef<TileDescriptor<T> | null>(fullscreenItem);
|
||||
latestFullscreenItem.current = fullscreenItem;
|
||||
const latestItems = useLatest(items)
|
||||
const latestFullscreenItem = useLatest(fullscreenItem)
|
||||
|
||||
const toggleFullscreen = useCallback(
|
||||
(itemId: string) => {
|
||||
|
||||
Reference in New Issue
Block a user