Remove dependency on matrix-react-sdk

This commit is contained in:
Robert Long
2022-04-07 14:22:36 -07:00
parent 46bcb8ac75
commit 72197c1a0a
30 changed files with 2610 additions and 1211 deletions

View File

@@ -2,7 +2,10 @@ import React, { useCallback, useEffect } from "react";
import { Modal, ModalContent } from "../Modal";
import { Button } from "../button";
import { FieldRow, InputField, ErrorMessage } from "../input/Input";
import { useSubmitRageshake, useRageshakeRequest } from "../settings/rageshake";
import {
useSubmitRageshake,
useRageshakeRequest,
} from "../settings/submit-rageshake";
import { Body } from "../typography/Typography";
import { randomString } from "matrix-js-sdk/src/randomstring";

View File

@@ -1,7 +1,7 @@
import React, { useCallback, useEffect, useState } from "react";
import { useHistory } from "react-router-dom";
import { GroupCallState } from "matrix-js-sdk/src/webrtc/groupCall";
import { useGroupCall } from "matrix-react-sdk/src/hooks/useGroupCall";
import { useGroupCall } from "./useGroupCall";
import { ErrorView, FullScreenView } from "../FullScreenView";
import { LobbyView } from "./LobbyView";
import { InCallView } from "./InCallView";
@@ -14,7 +14,6 @@ export function GroupCallView({
isPasswordlessUser,
roomId,
groupCall,
simpleGrid,
}) {
const [showInspector, setShowInspector] = useState(
() => !!localStorage.getItem("matrix-group-call-inspector")
@@ -89,7 +88,6 @@ export function GroupCallView({
isScreensharing={isScreensharing}
localScreenshareFeed={localScreenshareFeed}
screenshareFeeds={screenshareFeeds}
simpleGrid={simpleGrid}
setShowInspector={onChangeShowInspector}
showInspector={showInspector}
roomId={roomId}

View File

@@ -7,19 +7,15 @@ import {
ScreenshareButton,
} from "../button";
import { Header, LeftNav, RightNav, RoomHeaderInfo } from "../Header";
import VideoGrid, {
useVideoGridLayout,
} from "matrix-react-sdk/src/components/views/voip/GroupCallView/VideoGrid";
import { VideoTileContainer } from "matrix-react-sdk/src/components/views/voip/GroupCallView/VideoTileContainer";
import SimpleVideoGrid from "matrix-react-sdk/src/components/views/voip/GroupCallView/SimpleVideoGrid";
import "matrix-react-sdk/res/css/views/voip/GroupCallView/_VideoGrid.scss";
import { VideoGrid, useVideoGridLayout } from "../video-grid/VideoGrid";
import { VideoTileContainer } from "../video-grid/VideoTileContainer";
import { getAvatarUrl } from "../matrix-utils";
import { GroupCallInspector } from "./GroupCallInspector";
import { OverflowMenu } from "./OverflowMenu";
import { GridLayoutMenu } from "./GridLayoutMenu";
import { Avatar } from "../Avatar";
import { UserMenuContainer } from "../UserMenuContainer";
import { useRageshakeRequestModal } from "../settings/rageshake";
import { useRageshakeRequestModal } from "../settings/submit-rageshake";
import { RageshakeRequestModal } from "./RageshakeRequestModal";
import { usePreventScroll } from "@react-aria/overlays";
import { useMediaHandler } from "../settings/useMediaHandler";
@@ -44,7 +40,6 @@ export function InCallView({
toggleScreensharing,
isScreensharing,
screenshareFeeds,
simpleGrid,
setShowInspector,
showInspector,
roomId,
@@ -149,8 +144,6 @@ export function InCallView({
<div className={styles.centerMessage}>
<p>Waiting for other participants...</p>
</div>
) : simpleGrid ? (
<SimpleVideoGrid items={items} />
) : (
<VideoGrid
items={items}

View File

@@ -3,8 +3,8 @@ import styles from "./LobbyView.module.css";
import { Button, CopyButton, MicButton, VideoButton } from "../button";
import { Header, LeftNav, RightNav, RoomHeaderInfo } from "../Header";
import { GroupCallState } from "matrix-js-sdk/src/webrtc/groupCall";
import { useCallFeed } from "matrix-react-sdk/src/hooks/useCallFeed";
import { useMediaStream } from "matrix-react-sdk/src/hooks/useMediaStream";
import { useCallFeed } from "../video-grid/useCallFeed";
import { useMediaStream } from "../video-grid/useMediaStream";
import { getRoomUrl } from "../matrix-utils";
import { OverflowMenu } from "./OverflowMenu";
import { UserMenuContainer } from "../UserMenuContainer";

View File

@@ -2,7 +2,7 @@ import React, { useEffect } from "react";
import { Modal, ModalContent } from "../Modal";
import { Button } from "../button";
import { FieldRow, ErrorMessage } from "../input/Input";
import { useSubmitRageshake } from "../settings/rageshake";
import { useSubmitRageshake } from "../settings/submit-rageshake";
import { Body } from "../typography/Typography";
export function RageshakeRequestModal({ rageshakeRequestId, roomId, ...rest }) {

View File

@@ -29,9 +29,9 @@ export function RoomPage() {
const { roomId: maybeRoomId } = useParams();
const { hash, search } = useLocation();
const [simpleGrid, viaServers] = useMemo(() => {
const [viaServers] = useMemo(() => {
const params = new URLSearchParams(search);
return [params.has("simple"), params.getAll("via")];
return [params.getAll("via")];
}, [search]);
const roomId = (maybeRoomId || hash || "").toLowerCase();
@@ -56,7 +56,6 @@ export function RoomPage() {
roomId={roomId}
groupCall={groupCall}
isPasswordlessUser={isPasswordlessUser}
simpleGrid={simpleGrid}
/>
)}
</GroupCallLoader>

252
src/room/useGroupCall.js Normal file
View File

@@ -0,0 +1,252 @@
import { useCallback, useEffect, useState } from "react";
import {
GroupCallEvent,
GroupCallState,
} from "matrix-js-sdk/src/webrtc/groupCall";
import { usePageUnload } from "./usePageUnload";
export function useGroupCall(groupCall) {
const [
{
state,
calls,
localCallFeed,
activeSpeaker,
userMediaFeeds,
error,
microphoneMuted,
localVideoMuted,
isScreensharing,
screenshareFeeds,
localScreenshareFeed,
localDesktopCapturerSourceId,
participants,
hasLocalParticipant,
requestingScreenshare,
},
setState,
] = useState({
state: GroupCallState.LocalCallFeedUninitialized,
calls: [],
userMediaFeeds: [],
microphoneMuted: false,
localVideoMuted: false,
screenshareFeeds: [],
isScreensharing: false,
requestingScreenshare: false,
participants: [],
hasLocalParticipant: false,
});
const updateState = (state) =>
setState((prevState) => ({ ...prevState, ...state }));
useEffect(() => {
function onGroupCallStateChanged() {
updateState({
state: groupCall.state,
calls: [...groupCall.calls],
localCallFeed: groupCall.localCallFeed,
activeSpeaker: groupCall.activeSpeaker,
userMediaFeeds: [...groupCall.userMediaFeeds],
microphoneMuted: groupCall.isMicrophoneMuted(),
localVideoMuted: groupCall.isLocalVideoMuted(),
isScreensharing: groupCall.isScreensharing(),
localScreenshareFeed: groupCall.localScreenshareFeed,
localDesktopCapturerSourceId: groupCall.localDesktopCapturerSourceId,
screenshareFeeds: [...groupCall.screenshareFeeds],
participants: [...groupCall.participants],
});
}
function onUserMediaFeedsChanged(userMediaFeeds) {
updateState({
userMediaFeeds: [...userMediaFeeds],
});
}
function onScreenshareFeedsChanged(screenshareFeeds) {
updateState({
screenshareFeeds: [...screenshareFeeds],
});
}
function onActiveSpeakerChanged(activeSpeaker) {
updateState({
activeSpeaker: activeSpeaker,
});
}
function onLocalMuteStateChanged(microphoneMuted, localVideoMuted) {
updateState({
microphoneMuted,
localVideoMuted,
});
}
function onLocalScreenshareStateChanged(
isScreensharing,
localScreenshareFeed,
localDesktopCapturerSourceId
) {
updateState({
isScreensharing,
localScreenshareFeed,
localDesktopCapturerSourceId,
});
}
function onCallsChanged(calls) {
updateState({
calls: [...calls],
});
}
function onParticipantsChanged(participants) {
updateState({
participants: [...participants],
hasLocalParticipant: groupCall.hasLocalParticipant(),
});
}
groupCall.on(GroupCallEvent.GroupCallStateChanged, onGroupCallStateChanged);
groupCall.on(GroupCallEvent.UserMediaFeedsChanged, onUserMediaFeedsChanged);
groupCall.on(
GroupCallEvent.ScreenshareFeedsChanged,
onScreenshareFeedsChanged
);
groupCall.on(GroupCallEvent.ActiveSpeakerChanged, onActiveSpeakerChanged);
groupCall.on(GroupCallEvent.LocalMuteStateChanged, onLocalMuteStateChanged);
groupCall.on(
GroupCallEvent.LocalScreenshareStateChanged,
onLocalScreenshareStateChanged
);
groupCall.on(GroupCallEvent.CallsChanged, onCallsChanged);
groupCall.on(GroupCallEvent.ParticipantsChanged, onParticipantsChanged);
updateState({
error: null,
state: groupCall.state,
calls: [...groupCall.calls],
localCallFeed: groupCall.localCallFeed,
activeSpeaker: groupCall.activeSpeaker,
userMediaFeeds: [...groupCall.userMediaFeeds],
microphoneMuted: groupCall.isMicrophoneMuted(),
localVideoMuted: groupCall.isLocalVideoMuted(),
isScreensharing: groupCall.isScreensharing(),
localScreenshareFeed: groupCall.localScreenshareFeed,
localDesktopCapturerSourceId: groupCall.localDesktopCapturerSourceId,
screenshareFeeds: [...groupCall.screenshareFeeds],
participants: [...groupCall.participants],
hasLocalParticipant: groupCall.hasLocalParticipant(),
});
return () => {
groupCall.removeListener(
GroupCallEvent.GroupCallStateChanged,
onGroupCallStateChanged
);
groupCall.removeListener(
GroupCallEvent.UserMediaFeedsChanged,
onUserMediaFeedsChanged
);
groupCall.removeListener(
GroupCallEvent.ScreenshareFeedsChanged,
onScreenshareFeedsChanged
);
groupCall.removeListener(
GroupCallEvent.ActiveSpeakerChanged,
onActiveSpeakerChanged
);
groupCall.removeListener(
GroupCallEvent.LocalMuteStateChanged,
onLocalMuteStateChanged
);
groupCall.removeListener(
GroupCallEvent.LocalScreenshareStateChanged,
onLocalScreenshareStateChanged
);
groupCall.removeListener(GroupCallEvent.CallsChanged, onCallsChanged);
groupCall.removeListener(
GroupCallEvent.ParticipantsChanged,
onParticipantsChanged
);
groupCall.leave();
};
}, [groupCall]);
usePageUnload(() => {
groupCall.leave();
});
const initLocalCallFeed = useCallback(
() => groupCall.initLocalCallFeed(),
[groupCall]
);
const enter = useCallback(() => {
if (
groupCall.state !== GroupCallState.LocalCallFeedUninitialized &&
groupCall.state !== GroupCallState.LocalCallFeedInitialized
) {
return;
}
groupCall.enter().catch((error) => {
console.error(error);
updateState({ error });
});
}, [groupCall]);
const leave = useCallback(() => groupCall.leave(), [groupCall]);
const toggleLocalVideoMuted = useCallback(() => {
groupCall.setLocalVideoMuted(!groupCall.isLocalVideoMuted());
}, [groupCall]);
const toggleMicrophoneMuted = useCallback(() => {
groupCall.setMicrophoneMuted(!groupCall.isMicrophoneMuted());
}, [groupCall]);
const toggleScreensharing = useCallback(() => {
updateState({ requestingScreenshare: true });
groupCall.setScreensharingEnabled(!groupCall.isScreensharing()).then(() => {
updateState({ requestingScreenshare: false });
});
}, [groupCall]);
useEffect(() => {
if (window.RTCPeerConnection === undefined) {
const error = new Error(
"WebRTC is not supported or is being blocked in this browser."
);
console.error(error);
updateState({ error });
}
}, []);
return {
state,
calls,
localCallFeed,
activeSpeaker,
userMediaFeeds,
microphoneMuted,
localVideoMuted,
error,
initLocalCallFeed,
enter,
leave,
toggleLocalVideoMuted,
toggleMicrophoneMuted,
toggleScreensharing,
requestingScreenshare,
isScreensharing,
screenshareFeeds,
localScreenshareFeed,
localDesktopCapturerSourceId,
participants,
hasLocalParticipant,
};
}

54
src/room/usePageUnload.js Normal file
View File

@@ -0,0 +1,54 @@
import { useEffect } from "react";
// https://stackoverflow.com/a/9039885
function isIOS() {
return (
[
"iPad Simulator",
"iPhone Simulator",
"iPod Simulator",
"iPad",
"iPhone",
"iPod",
].includes(navigator.platform) ||
// iPad on iOS 13 detection
(navigator.userAgent.includes("Mac") && "ontouchend" in document)
);
}
export function usePageUnload(callback) {
useEffect(() => {
let pageVisibilityTimeout;
function onBeforeUnload(event) {
if (event.type === "visibilitychange") {
if (document.visibilityState === "visible") {
clearTimeout(pageVisibilityTimeout);
} else {
// Wait 5 seconds before closing the page to avoid accidentally leaving
// TODO: Make this configurable?
pageVisibilityTimeout = setTimeout(() => {
callback();
}, 5000);
}
} else {
callback();
}
}
// iOS doesn't fire beforeunload event, so leave the call when you hide the page.
if (isIOS()) {
window.addEventListener("pagehide", onBeforeUnload);
document.addEventListener("visibilitychange", onBeforeUnload);
}
window.addEventListener("beforeunload", onBeforeUnload);
return () => {
window.removeEventListener("pagehide", onBeforeUnload);
document.removeEventListener("visibilitychange", onBeforeUnload);
window.removeEventListener("beforeunload", onBeforeUnload);
clearTimeout(pageVisibilityTimeout);
};
}, [callback]);
}