diff --git a/package.json b/package.json
index 8651344..80e47e2 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
- "@epicgames-ps/lib-pixelstreamingfrontend-ue5.3": "^1.0.1",
+ "@epicgames-ps/lib-pixelstreamingfrontend-ue5.3": "^1.0.4",
"@epicgames-ps/lib-pixelstreamingfrontend-ue5.5": "^0.0.12",
"@livekit/components-react": "^2.0.3",
"@livekit/components-styles": "^1.0.10",
diff --git a/src/components/ChatNew.tsx b/src/components/ChatNew.tsx
index 2f33857..f801f7e 100644
--- a/src/components/ChatNew.tsx
+++ b/src/components/ChatNew.tsx
@@ -80,90 +80,6 @@ function ChatNew({ isShow, socket, userId, name, onClose }: ChatNewProps) {
}, [isShow]);
return (
- //
- //
- //
- //
Чат
- //
- // }
- // onlyIcon
- // onClick={onClose}
- // />
- //
- //
- //
- // {messages.map((message) => (
- //
- // {message.user.id !== userId && (
- //
- //
- // {message.user.name[0].toUpperCase()}
- //
- //
- // )}
- //
- //
- // {message.user.id !== userId && (
- //
- // {message.user.name}
- //
- // )}
- //
- // {message.text}
- //
- //
- // {message.time}
- //
- //
- // {message.user.id !== userId && (
- //
- //
- //
- // )}
- //
- //
- // ))}
- //
- //
- //
- //
- //
- //
-
(null);
const isSpeaking = useIsAudioActive({ source: mediaStream });
const [_muted, setMuted] = useState(muted);
+ const [isLoading, setIsLoading] = useState(true);
function toggleSound() {
if (!remoteVideoRef.current) return;
@@ -30,6 +31,10 @@ function Video({ mediaStream, muted, user }: Props) {
remoteVideoRef.current.onloadedmetadata = () => {
remoteVideoRef.current?.play();
};
+
+ remoteVideoRef.current.onplay = () => {
+ setIsLoading(false);
+ };
}, [mediaStream]);
useEffect(() => {
@@ -55,6 +60,15 @@ function Video({ mediaStream, muted, user }: Props) {
{_muted ? : }
+ {isLoading && (
+
+

+
+ )}
);
}
diff --git a/src/components/modals/stream/InviteModal.tsx b/src/components/modals/stream/InviteModal.tsx
new file mode 100644
index 0000000..31940eb
--- /dev/null
+++ b/src/components/modals/stream/InviteModal.tsx
@@ -0,0 +1,96 @@
+import { Trans } from "react-i18next";
+import QRCode from "react-qr-code";
+import CloseIcon from "../../icons/CloseIcon";
+import LinkIcon from "../../icons/LinkIcon";
+import Button from "../../ui/Button";
+import useModalStore from "../../../stores/useModalStore";
+import { useClipboard } from "use-clipboard-copy";
+import { toast, Bounce, ToastContainer } from "react-toastify";
+import InfoIcon from "../../icons/InfoBlueIcon";
+
+function InviteModal() {
+ const { setModal } = useModalStore();
+ const clipboard = useClipboard();
+ const link = window.location.origin + window.location.pathname;
+
+ function handleClickClipboard() {
+ clipboard.copy();
+
+ toast.info("Ссылка скопирована в буфер обмена", {
+ icon: ,
+ position: "top-center",
+ autoClose: 3000,
+ hideProgressBar: true,
+ closeOnClick: true,
+ pauseOnHover: true,
+ draggable: true,
+ progress: undefined,
+ theme: "light",
+ transition: Bounce,
+ });
+ }
+
+ return (
+
+
+
+
+ Пригласить
+
+
}
+ onlyIcon
+ onClick={() => setModal(null)}
+ />
+
+
+
+
+
+
+ Отсканируйте QR-код,
+
+ чтобы присоедениться
+
к демонстрации
+
+
+
+
+ }
+ fullWidth
+ large
+ onClick={handleClickClipboard}
+ >
+
+ Скопировать ссылку для подключения
+
+
+
+
+ {/*
+
+
*/}
+
+
+
+
+
+ );
+}
+
+export default InviteModal;
diff --git a/src/pages/StreamPage3.tsx b/src/pages/StreamPage3.tsx
index 1191c50..d95d539 100644
--- a/src/pages/StreamPage3.tsx
+++ b/src/pages/StreamPage3.tsx
@@ -24,6 +24,13 @@ import MicroOnIcon from "../components/icons/MicroOnIcon";
import MicroOffIcon from "../components/icons/MicroOffIcon";
import CameraOnIcon from "../components/icons/CameraOnIcon";
import CameraOffIcon from "../components/icons/CameraOffIcon";
+import { Trans } from "react-i18next";
+import { isIOS } from "react-device-detect";
+import WindowIcon from "../components/icons/WindowIcon";
+import FullscreenIcon from "../components/icons/FullscreenIcon";
+import ShareIcon from "../components/icons/ShareIcon";
+import { useFullscreen } from "ahooks";
+import InviteModal from "../components/modals/stream/InviteModal";
// import MoreIcon from "../components/icons/MoreIcon";
@@ -55,6 +62,10 @@ function StreamPage3() {
const { name } = useStreamStore();
const [isMicEnabled, setIsMicEnabled] = useState(true);
const [isCameraEnabled, setIsCameraEnabled] = useState(true);
+ const [isEnded, setIsEnded] = useState();
+ const [, setEndAt] = useState();
+ const fullscreenRef = useRef(null);
+ const [isFullscreen, { toggleFullscreen }] = useFullscreen(fullscreenRef);
async function startCall(remotePeerId: string) {
if (!peerInstance) return;
@@ -152,6 +163,10 @@ function StreamPage3() {
setMe(users.find((user) => user.id === userId));
});
+ socket.on("request-control", (userId) => {
+ console.log("request-control", userId);
+ });
+
socket.on("connect", () => {
setSocket(socket);
});
@@ -192,37 +207,59 @@ function StreamPage3() {
}, 500);
}
- async function getActiveSession() {
- const activeSession: any = await api
- .get(`activeSessions/${params.id}`)
- .json();
-
- // if (activeSession?.endAt) {
- // setEndAt(activeSession.endAt);
- // }
-
- return activeSession;
- }
-
async function getWSUrl() {
const activeSession = await getActiveSession();
if (!activeSession || activeSession.status === "error") {
+ setIsEnded(true);
return;
}
+ setIsEnded(false);
setWSUrl(
`wss://${activeSession.location}.sess.stream.graff.tech/${activeSession.name}/${activeSession.cirrusPort}/`
);
+ setModal();
+
+ checkSessionStatus();
}
function transferControl(userId: string) {
socket?.emit("transfer-control", userId);
}
+ function requestControl(userId: string) {
+ console.log("requestControl func", userId);
+ socket?.emit("request-control", userId);
+ }
+
+ async function getActiveSession() {
+ const activeSession: any = await api
+ .get(`activeSessions/${params.id}`)
+ .json();
+
+ if (activeSession?.endAt) {
+ setEndAt(activeSession.endAt);
+ }
+
+ return activeSession;
+ }
+
+ async function checkSessionStatus() {
+ const activeSession = await getActiveSession();
+
+ if (!activeSession || activeSession.status === "error") {
+ setIsEnded(true);
+ return;
+ }
+
+ setTimeout(async () => {
+ await checkSessionStatus();
+ }, 1000);
+ }
+
useEffect(() => {
getWSUrl();
- setModal();
}, []);
useEffect(() => {
@@ -244,123 +281,162 @@ function StreamPage3() {
}, [users.length]);
return (
-
-
-
-

-
-
-
-
-
{name[0]?.toUpperCase()}
- {me?.isControlAllowed && (
-
- )}
+
+ {isEnded === false ? (
+ <>
+
+
+
-
{name}
-
-
-
:
}
- onlyIcon
- onClick={() => me?.isAdmin && transferControl(me.id)}
- />
+
+
+
+
+ {name[0]?.toUpperCase()}
+
+ {me?.isControlAllowed && (
+
+ )}
+
+
{name}
+
+
+ : }
+ onlyIcon
+ onClick={() =>
+ me!.isAdmin
+ ? transferControl(me!.id)
+ : requestControl(me!.id)
+ }
+ />
+ : }
+ onlyIcon
+ onClick={toggleMic}
+ />
+ : }
+ onlyIcon
+ onClick={toggleCamera}
+ />
+
+
+ {users.map((user) => {
+ if (user.id !== userId) {
+ return (
+
+
+
+ {name[0]?.toUpperCase()}
+
+ {user?.isControlAllowed && (
+
+ )}
+
+
{user.name}
-
:
}
- onlyIcon
- onClick={toggleMic}
- />
-
:
}
- onlyIcon
- onClick={toggleCamera}
- />
-
-
- {users.map((user) => {
- if (user.id !== userId) {
- return (
-
-
-
- {name[0]?.toUpperCase()}
-
- {user?.isControlAllowed && (
-
- )}
-
-
{user.name}
-
- {me?.isAdmin && me?.isControlAllowed && (
-
- {/*
+ )}
- )}
-
- );
- }
- })}
-
-
-
- {WSUrl && (
-
- )}
-
-
-
-
-
-
{name}
+ );
+ }
+ })}
+
+
+ }
+ onlyIcon
+ onClick={() => setModal()}
+ />
+ {!isIOS && (
+ : }
+ onlyIcon
+ onClick={toggleFullscreen}
+ />
+ )}
- {remoteStreams.map(({ peerId, mediaStream }) => (
-
-
+
+ {WSUrl && (
+
+ )}
-
+ {!users.find((user) => user.id === userId)?.isControlAllowed && (
+
alert("")}
+ >
+ )}
+
+
+
+ {remoteStreams.map(({ peerId, mediaStream }) => (
+
+
+
+ >
+ ) : (
+
+
+
+ Данная демонстрация была завершена
+
+
+
+ )}
);
}
diff --git a/yarn.lock b/yarn.lock
index fbd73ee..09f7bf4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -36,10 +36,10 @@
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.1.tgz#e93c13942592cf5ef01aa8297444dc192beee52f"
integrity sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==
-"@epicgames-ps/lib-pixelstreamingfrontend-ue5.3@^1.0.1":
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/@epicgames-ps/lib-pixelstreamingfrontend-ue5.3/-/lib-pixelstreamingfrontend-ue5.3-1.0.1.tgz#ba7d0fb42ede74109fcbb2510d7f6a4442bed7a0"
- integrity sha512-DLeMbwi/szf4/rQAPXFl1YH5lT5kHJ2GcnxYNPvYVWZ9xgX5hjieREXyi8DaxCAPF81e+ev57TjZKJy7R3tvpw==
+"@epicgames-ps/lib-pixelstreamingfrontend-ue5.3@^1.0.4":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@epicgames-ps/lib-pixelstreamingfrontend-ue5.3/-/lib-pixelstreamingfrontend-ue5.3-1.0.4.tgz#71533a4f940627702d26896eb3380d08c6d05523"
+ integrity sha512-gqt2lFGLys3YOvloK9X/gpk+ZPgRlLi+uB9kWWWMJd+Gih0jgRwc6GJ0b+LuIVmZau4qNUbTmfOklKpti0G07g==
dependencies:
sdp "^3.1.0"