From f2ab9800d4bd77c1ab8e035e366877402e18a985 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Thu, 29 Apr 2021 22:18:11 +0200 Subject: [PATCH] Rendering the main UI only via IPC --- shared/js/ui/AppController.ts | 56 ++++----- shared/js/ui/AppDefinitions.ts | 25 +++- shared/js/ui/AppRenderer.tsx | 109 +++++++++++------- shared/js/ui/frames/SideBarController.ts | 21 +--- shared/js/ui/frames/SideBarDefinitions.ts | 18 ++- shared/js/ui/frames/SideBarRenderer.tsx | 32 +++-- .../js/ui/frames/side/ChannelBarController.ts | 6 +- .../ui/frames/side/ChannelBarDefinitions.ts | 8 +- .../js/ui/frames/side/ChannelBarRenderer.tsx | 17 +-- shared/js/ui/frames/video/Controller.ts | 15 +-- shared/js/ui/frames/video/Definitions.ts | 13 ++- shared/js/ui/frames/video/Renderer.tsx | 19 ++- shared/js/ui/react-elements/Helper.ts | 9 ++ web/app/WebWindowManager.ts | 3 + 14 files changed, 212 insertions(+), 139 deletions(-) diff --git a/shared/js/ui/AppController.ts b/shared/js/ui/AppController.ts index 9d0cf7a2..c58eed9f 100644 --- a/shared/js/ui/AppController.ts +++ b/shared/js/ui/AppController.ts @@ -9,20 +9,22 @@ import {initializeConnectionListController} from "tc-shared/ui/frames/connection import * as loader from "tc-loader"; import {Stage} from "tc-loader"; import {server_connections} from "tc-shared/ConnectionManager"; -import {AppUiEvents} from "tc-shared/ui/AppDefinitions"; +import {AppUiEvents, AppUiVariables} from "tc-shared/ui/AppDefinitions"; import {ConnectionHandler} from "tc-shared/ConnectionHandler"; import {SideBarController} from "tc-shared/ui/frames/SideBarController"; import {ServerEventLogController} from "tc-shared/ui/frames/log/Controller"; import {HostBannerController} from "tc-shared/ui/frames/HostBannerController"; +import {UiVariableProvider} from "tc-shared/ui/utils/Variable"; +import {createIpcUiVariableProvider, IpcUiVariableProvider} from "tc-shared/ui/utils/IpcVariable"; export class AppController { - private uiEvents: Registry; - private listener: (() => void)[]; private currentConnection: ConnectionHandler; private listenerConnection: (() => void)[]; + private variables: IpcUiVariableProvider; + private container: HTMLDivElement; private controlBarEvents: Registry; private connectionListEvents: Registry; @@ -32,9 +34,21 @@ export class AppController { private hostBannerController: HostBannerController; constructor() { - this.uiEvents = new Registry(); - this.uiEvents.on("query_channel_tree", () => this.notifyChannelTree()); - this.uiEvents.on("query_video", () => this.notifyVideoContainer()); + this.variables = createIpcUiVariableProvider(); + this.variables.setVariableProvider("connectionList", () => this.connectionListEvents.generateIpcDescription()); + this.variables.setVariableProvider("controlBar", () => this.controlBarEvents.generateIpcDescription()); + this.variables.setVariableProvider("hostBanner", () => this.hostBannerController.uiEvents.generateIpcDescription()); + this.variables.setVariableProvider("log", () => this.serverLogController.events.generateIpcDescription()); + this.variables.setVariableProvider("sidebar", () => this.sideBarController.uiEvents.generateIpcDescription()); + this.variables.setVariableProvider("sidebarHeader", () => this.sideBarController.getHeaderController().uiEvents.generateIpcDescription()); + this.variables.setVariableProvider("channelTree", () => ({ + events: this.currentConnection?.channelTree.mainTreeUiEvents.generateIpcDescription(), + handlerId: this.currentConnection?.handlerId + })); + this.variables.setVariableProvider("channelVideo", () => ({ + events: this.currentConnection?.video_frame.getEvents().generateIpcDescription(), + handlerId: this.currentConnection?.handlerId + })); this.listener = []; } @@ -64,8 +78,8 @@ export class AppController { this.hostBannerController?.destroy(); this.hostBannerController = undefined; - this.uiEvents?.destroy(); - this.uiEvents = undefined; + this.variables?.destroy(); + this.variables = undefined; } initialize() { @@ -102,35 +116,15 @@ export class AppController { this.serverLogController.setConnectionHandler(connection); this.hostBannerController.setConnectionHandler(connection); - this.notifyChannelTree(); - this.notifyVideoContainer(); + this.variables.sendVariable("channelTree"); + this.variables.sendVariable("channelVideo"); } renderApp() { ReactDOM.render(React.createElement(TeaAppMainView, { - controlBar: this.controlBarEvents, - connectionList: this.connectionListEvents, - sidebar: this.sideBarController.uiEvents, - sidebarHeader: this.sideBarController.getHeaderController().uiEvents, - log: this.serverLogController.events, - events: this.uiEvents, - hostBanner: this.hostBannerController.uiEvents + variables: this.variables.generateConsumerDescription(), }), this.container); } - - private notifyChannelTree() { - this.uiEvents.fire_react("notify_channel_tree", { - handlerId: this.currentConnection?.handlerId, - events: this.currentConnection?.channelTree.mainTreeUiEvents - }); - } - - private notifyVideoContainer() { - this.uiEvents.fire_react("notify_video", { - events: this.currentConnection?.video_frame.getEvents(), - handlerId: this.currentConnection?.handlerId - }); - } } export let appViewController: AppController; diff --git a/shared/js/ui/AppDefinitions.ts b/shared/js/ui/AppDefinitions.ts index 6db8e80c..a2d352ed 100644 --- a/shared/js/ui/AppDefinitions.ts +++ b/shared/js/ui/AppDefinitions.ts @@ -1,6 +1,29 @@ -import {Registry} from "tc-shared/events"; +import {IpcRegistryDescription, Registry} from "tc-shared/events"; import {ChannelTreeUIEvents} from "tc-shared/ui/tree/Definitions"; import {ChannelVideoEvents} from "tc-shared/ui/frames/video/Definitions"; +import {ControlBarEvents} from "tc-shared/ui/frames/control-bar/Definitions"; +import {ConnectionListUIEvents} from "tc-shared/ui/frames/connection-handler-list/Definitions"; +import {SideBarEvents} from "tc-shared/ui/frames/SideBarDefinitions"; +import {SideHeaderEvents} from "tc-shared/ui/frames/side/HeaderDefinitions"; +import {ServerEventLogUiEvents} from "tc-shared/ui/frames/log/Definitions"; +import {HostBannerUiEvents} from "tc-shared/ui/frames/HostBannerDefinitions"; + +export interface AppUiVariables { + readonly channelTree: { + events: IpcRegistryDescription | undefined, + handlerId: string + }, + readonly channelVideo: { + events: IpcRegistryDescription, + handlerId: string + }, + readonly controlBar: IpcRegistryDescription, + readonly connectionList: IpcRegistryDescription, + readonly sidebar: IpcRegistryDescription, + readonly sidebarHeader: IpcRegistryDescription, + readonly log: IpcRegistryDescription, + readonly hostBanner: IpcRegistryDescription, +} export interface AppUiEvents { query_channel_tree: {}, diff --git a/shared/js/ui/AppRenderer.tsx b/shared/js/ui/AppRenderer.tsx index c77f6a07..e05b8e86 100644 --- a/shared/js/ui/AppRenderer.tsx +++ b/shared/js/ui/AppRenderer.tsx @@ -1,96 +1,117 @@ import * as React from "react"; -import {useState} from "react"; +import {useEffect, useMemo} from "react"; import {ControlBar2} from "tc-shared/ui/frames/control-bar/Renderer"; -import {Registry} from "tc-shared/events"; -import {ControlBarEvents} from "tc-shared/ui/frames/control-bar/Definitions"; -import {ConnectionListUIEvents} from "tc-shared/ui/frames/connection-handler-list/Definitions"; +import {IpcRegistryDescription, Registry} from "tc-shared/events"; import {ConnectionHandlerList} from "tc-shared/ui/frames/connection-handler-list/Renderer"; import {ErrorBoundary} from "tc-shared/ui/react-elements/ErrorBoundary"; import {ContextDivider} from "tc-shared/ui/react-elements/ContextDivider"; import {SideBarRenderer} from "tc-shared/ui/frames/SideBarRenderer"; -import {SideBarEvents} from "tc-shared/ui/frames/SideBarDefinitions"; -import {SideHeaderEvents} from "tc-shared/ui/frames/side/HeaderDefinitions"; import {ServerLogFrame} from "tc-shared/ui/frames/log/Renderer"; -import {ServerEventLogUiEvents} from "tc-shared/ui/frames/log/Definitions"; import {FooterRenderer} from "tc-shared/ui/frames/footer/Renderer"; import {HostBanner} from "tc-shared/ui/frames/HostBannerRenderer"; -import {HostBannerUiEvents} from "tc-shared/ui/frames/HostBannerDefinitions"; -import {AppUiEvents} from "tc-shared/ui/AppDefinitions"; +import {AppUiVariables} from "tc-shared/ui/AppDefinitions"; import {ChannelTreeRenderer} from "tc-shared/ui/tree/Renderer"; -import {ChannelTreeUIEvents} from "tc-shared/ui/tree/Definitions"; import {ImagePreviewHook} from "tc-shared/ui/frames/ImagePreview"; import {InternalModalHook} from "tc-shared/ui/react-elements/modal/internal"; import {TooltipHook} from "tc-shared/ui/react-elements/Tooltip"; -import {ChannelVideoEvents} from "tc-shared/ui/frames/video/Definitions"; import {ChannelVideoRenderer} from "tc-shared/ui/frames/video/Renderer"; - +import { + createIpcUiVariableConsumer, + IpcVariableDescriptor +} from "tc-shared/ui/utils/IpcVariable"; +import {UiVariableConsumer} from "tc-shared/ui/utils/Variable"; +import {useRegistry} from "tc-shared/ui/react-elements/Helper"; const cssStyle = require("./AppRenderer.scss"); -const VideoFrame = React.memo((props: { events: Registry }) => { - const [ data, setData ] = useState<{ events: Registry | undefined, handlerId: string | undefined }>(() => { - props.events.fire("query_video"); - return { events: undefined, handlerId: undefined }; - }); - props.events.reactUse("notify_video", event => setData({ handlerId: event.handlerId, events: event.events })); + +const VideoFrame = React.memo((props: { variables: UiVariableConsumer }) => { + const data = props.variables.useReadOnly("channelVideo", undefined, { handlerId: undefined, events: undefined }); + const events = useRegistry(data.events); if(!data.events) { return null; } - return ; + return ; }); -const ChannelTree = React.memo((props: { events: Registry }) => { - const [ data, setData ] = useState<{ events: Registry, handlerId: string }>(() => { - props.events.fire("query_channel_tree"); - return undefined; - }); +const ChannelTree = React.memo((props: { variables: UiVariableConsumer }) => { + const data = props.variables.useReadOnly("channelTree", undefined, { handlerId: undefined, events: undefined }); + const events = useRegistry(data.events); - props.events.reactUse("notify_channel_tree", event => { - setData({ events: event.events, handlerId: event.handlerId }); - }, undefined, []); - - if(!data?.events) { + if(!events) { return null; } - return ; + return ; }); +const SideBar = React.memo((props: { variables: UiVariableConsumer }) => ( + + {sidebarRegistry => ( + + {sidebarHeaderRegistry => sidebarRegistry && sidebarHeaderRegistry ? ( + + ) : null} + + )} + +)); + +function EventProvider(props: { + registry: IpcRegistryDescription | undefined, + children: (registry: Registry | undefined) => React.ReactElement +}) : React.ReactElement { + return props.children(useRegistry(props.registry)); +} + export const TeaAppMainView = (props: { - events: Registry - controlBar: Registry, - connectionList: Registry, - sidebar: Registry, - sidebarHeader: Registry, - log: Registry, - hostBanner: Registry + variables: IpcVariableDescriptor, }) => { + const variables = useMemo(() => createIpcUiVariableConsumer(props.variables), [ props.variables ]); + useEffect(() => () => variables.destroy(), [ props.variables ]); + return (
- + + {registry => registry ? ( + + ) : null} + - + + {registry => registry ? ( + + ) : null} +
- +
- - + + {registry => registry ? ( + + ) : null} + +
- +
- + + {registry => registry ? ( + + ) : null} +
diff --git a/shared/js/ui/frames/SideBarController.ts b/shared/js/ui/frames/SideBarController.ts index 27e5e3f4..9c3fc97a 100644 --- a/shared/js/ui/frames/SideBarController.ts +++ b/shared/js/ui/frames/SideBarController.ts @@ -73,15 +73,6 @@ export class SideBarController { this.privateConversations = undefined; } - renderInto(container: HTMLDivElement) { - /* - ReactDOM.render(React.createElement(SideBarRenderer, { - events: this.uiEvents, - eventsHeader: this.header["uiEvents"], - }), container); - */ - } - getMusicController() : MusicBotController { return this.musicPanel; } @@ -116,7 +107,7 @@ export class SideBarController { this.uiEvents.fire_react("notify_content_data", { content: "channel", data: { - events: this.channelBar.uiEvents, + events: this.channelBar.uiEvents.generateIpcDescription(), } }); break; @@ -125,7 +116,7 @@ export class SideBarController { this.uiEvents.fire_react("notify_content_data", { content: "server", data: this.currentConnection ? { - chatEvents: this.channelBar.getChannelConversationController().getUiEvents(), + chatEvents: this.channelBar.getChannelConversationController().getUiEvents().generateIpcDescription(), handlerId: this.currentConnection.handlerId } : undefined }); @@ -140,7 +131,7 @@ export class SideBarController { this.uiEvents.fire_react("notify_content_data", { content: "private-chat", data: { - events: this.privateConversations["uiEvents"], + events: this.privateConversations["uiEvents"].generateIpcDescription(), handlerId: this.currentConnection.handlerId } }); @@ -155,7 +146,7 @@ export class SideBarController { this.uiEvents.fire_react("notify_content_data", { content: "client-info", data: { - events: this.clientInfo["uiEvents"], + events: this.clientInfo["uiEvents"].generateIpcDescription(), } }); break; @@ -169,8 +160,8 @@ export class SideBarController { this.uiEvents.fire_react("notify_content_data", { content: "music-manage", data: { - botEvents: this.musicPanel.getBotUiEvents(), - playlistEvents: this.musicPanel.getPlaylistUiEvents() + botEvents: this.musicPanel.getBotUiEvents().generateIpcDescription(), + playlistEvents: this.musicPanel.getPlaylistUiEvents().generateIpcDescription() } }); break; diff --git a/shared/js/ui/frames/SideBarDefinitions.ts b/shared/js/ui/frames/SideBarDefinitions.ts index 78f4b263..985ffe47 100644 --- a/shared/js/ui/frames/SideBarDefinitions.ts +++ b/shared/js/ui/frames/SideBarDefinitions.ts @@ -1,4 +1,4 @@ -import {Registry} from "tc-shared/events"; +import {IpcRegistryDescription, Registry} from "tc-shared/events"; import {PrivateConversationUIEvents} from "tc-shared/ui/frames/side/PrivateConversationDefinitions"; import {ClientInfoEvents} from "tc-shared/ui/frames/side/ClientInfoDefinitions"; import {SideHeaderEvents} from "tc-shared/ui/frames/side/HeaderDefinitions"; @@ -7,28 +7,26 @@ import {MusicBotUiEvents} from "tc-shared/ui/frames/side/MusicBotDefinitions"; import {MusicPlaylistUiEvents} from "tc-shared/ui/frames/side/MusicPlaylistDefinitions"; import {ChannelConversationUiEvents} from "tc-shared/ui/frames/side/ChannelConversationDefinitions"; -/* TODO: Somehow outsource the event registries to IPC? */ - export type SideBarType = "none" | "server" | "channel" | "private-chat" | "client-info" | "music-manage"; export interface SideBarTypeData { "none": {}, "channel": { - events: Registry + events: IpcRegistryDescription }, "private-chat": { - events: Registry, + events: IpcRegistryDescription, handlerId: string }, "client-info": { - events: Registry, + events: IpcRegistryDescription, }, "music-manage": { - botEvents: Registry, - playlistEvents: Registry + botEvents: IpcRegistryDescription, + playlistEvents: IpcRegistryDescription }, "server": { handlerId: string, - chatEvents: Registry + chatEvents: IpcRegistryDescription } } @@ -40,9 +38,7 @@ export type SideBarNotifyContentData = { export interface SideBarEvents { query_content: {}, query_content_data: { content: SideBarType }, - query_header_data: {}, notify_content: { content: SideBarType }, notify_content_data: SideBarNotifyContentData, - notify_header_data: { events: Registry } } \ No newline at end of file diff --git a/shared/js/ui/frames/SideBarRenderer.tsx b/shared/js/ui/frames/SideBarRenderer.tsx index 297a94e6..08e0b3ac 100644 --- a/shared/js/ui/frames/SideBarRenderer.tsx +++ b/shared/js/ui/frames/SideBarRenderer.tsx @@ -11,6 +11,7 @@ import {ErrorBoundary} from "tc-shared/ui/react-elements/ErrorBoundary"; import {MusicBotRenderer} from "tc-shared/ui/frames/side/MusicBotRenderer"; import {ConversationPanel} from "tc-shared/ui/frames/side/AbstractConversationRenderer"; import React = require("react"); +import {useRegistry} from "tc-shared/ui/react-elements/Helper"; const cssStyle = require("./SideBarRenderer.scss"); @@ -29,24 +30,28 @@ function useContentData(type: T) : SideBarTypeData[T] { const ContentRendererChannel = () => { const contentData = useContentData("channel"); - if(!contentData) { return null; } + const events = useRegistry(contentData?.events); + + if(!contentData || !events) { return null; } return ( ); }; const ContentRendererServer = () => { const contentData = useContentData("server"); - if(!contentData) { return null; } + const events = useRegistry(contentData?.chatEvents); + + if(!contentData || !events) { return null; } return ( { const ContentRendererPrivateConversation = () => { const contentData = useContentData("private-chat"); - if(!contentData) { return null; } + const events = useRegistry(contentData?.events); + + if(!contentData || !events) { return null; } return ( ); @@ -69,23 +76,26 @@ const ContentRendererPrivateConversation = () => { const ContentRendererClientInfo = () => { const contentData = useContentData("client-info"); - if(!contentData) { return null; } + const events = useRegistry(contentData?.events); + if(!contentData || !events) { return null; } return ( ); }; const ContentRendererMusicManage = () => { const contentData = useContentData("music-manage"); - if(!contentData) { return null; } + const botEvents = useRegistry(contentData?.botEvents); + const playlistEvents = useRegistry(contentData?.playlistEvents); + if(!contentData || !botEvents || !playlistEvents) { return null; } return ( ); }; diff --git a/shared/js/ui/frames/side/ChannelBarController.ts b/shared/js/ui/frames/side/ChannelBarController.ts index 75ad6eb5..dd1efe98 100644 --- a/shared/js/ui/frames/side/ChannelBarController.ts +++ b/shared/js/ui/frames/side/ChannelBarController.ts @@ -181,7 +181,7 @@ export class ChannelBarController { this.uiEvents.fire_react("notify_data", { content: "conversation", data: { - events: this.channelConversations.getUiEvents() + events: this.channelConversations.getUiEvents().generateIpcDescription() } }); break; @@ -190,7 +190,7 @@ export class ChannelBarController { this.uiEvents.fire_react("notify_data", { content: "description", data: { - events: this.description.uiEvents + events: this.description.uiEvents.generateIpcDescription() } }); break; @@ -199,7 +199,7 @@ export class ChannelBarController { this.uiEvents.fire_react("notify_data", { content: "file-transfer", data: { - events: this.fileBrowser.uiEvents + events: this.fileBrowser.uiEvents.generateIpcDescription() } }); break; diff --git a/shared/js/ui/frames/side/ChannelBarDefinitions.ts b/shared/js/ui/frames/side/ChannelBarDefinitions.ts index 51d552ed..9ec45cb6 100644 --- a/shared/js/ui/frames/side/ChannelBarDefinitions.ts +++ b/shared/js/ui/frames/side/ChannelBarDefinitions.ts @@ -1,4 +1,4 @@ -import {Registry} from "tc-shared/events"; +import {IpcRegistryDescription} from "tc-shared/events"; import {ChannelConversationUiEvents} from "tc-shared/ui/frames/side/ChannelConversationDefinitions"; import {ChannelDescriptionUiEvents} from "tc-shared/ui/frames/side/ChannelDescriptionDefinitions"; import {ChannelFileBrowserUiEvents} from "tc-shared/ui/frames/side/ChannelFileBrowserDefinitions"; @@ -7,13 +7,13 @@ export type ChannelBarMode = "conversation" | "description" | "file-transfer" | export interface ChannelBarModeData { "conversation": { - events: Registry, + events: IpcRegistryDescription, }, "description": { - events: Registry + events: IpcRegistryDescription }, "file-transfer": { - events: Registry + events: IpcRegistryDescription }, "none": {} } diff --git a/shared/js/ui/frames/side/ChannelBarRenderer.tsx b/shared/js/ui/frames/side/ChannelBarRenderer.tsx index 9103c6ce..7baa30e3 100644 --- a/shared/js/ui/frames/side/ChannelBarRenderer.tsx +++ b/shared/js/ui/frames/side/ChannelBarRenderer.tsx @@ -3,7 +3,7 @@ import {ChannelBarMode, ChannelBarModeData, ChannelBarUiEvents} from "tc-shared/ import * as React from "react"; import {useContext, useState} from "react"; import {ConversationPanel} from "tc-shared/ui/frames/side/AbstractConversationRenderer"; -import {useDependentState} from "tc-shared/ui/react-elements/Helper"; +import {useDependentState, useRegistry} from "tc-shared/ui/react-elements/Helper"; import {ChannelDescriptionRenderer} from "tc-shared/ui/frames/side/ChannelDescriptionRenderer"; import {ChannelFileBrowser} from "tc-shared/ui/frames/side/ChannelFileBrowserRenderer"; @@ -49,12 +49,13 @@ const ModeRenderer = () => { const ModeRendererConversation = React.memo(() => { const channelContext = useContext(ChannelContext); const data = useModeData("conversation", [ channelContext ]); - if(!data) { return null; } + const events = useRegistry(data?.events); + if(!data || !events) { return null; } return ( { const ModeRendererDescription = React.memo(() => { const channelContext = useContext(ChannelContext); const data = useModeData("description", [ channelContext ]); - if(!data) { return null; } + const events = useRegistry(data?.events); + if(!data || !events) { return null; } return ( - + ); }); const ModeRendererFileTransfer = React.memo(() => { const channelContext = useContext(ChannelContext); const data = useModeData("file-transfer", [ channelContext ]); - if(!data) { return null; } + const events = useRegistry(data?.events); + if(!data || !events) { return null; } return ( - + ); }); diff --git a/shared/js/ui/frames/video/Controller.ts b/shared/js/ui/frames/video/Controller.ts index 395c6721..17be8abb 100644 --- a/shared/js/ui/frames/video/Controller.ts +++ b/shared/js/ui/frames/video/Controller.ts @@ -1,11 +1,8 @@ import {ConnectionHandler} from "tc-shared/ConnectionHandler"; -import * as React from "react"; -import * as ReactDOM from "react-dom"; -import {ChannelVideoRenderer} from "tc-shared/ui/frames/video/Renderer"; import {Registry} from "tc-shared/events"; import { ChannelVideoEvents, - ChannelVideoStreamState, + ChannelVideoStreamState, getVideoStreamMap, kLocalVideoId, VideoStreamState } from "tc-shared/ui/frames/video/Definitions"; @@ -24,8 +21,7 @@ import * as _ from "lodash"; import PermissionType from "tc-shared/permission/PermissionType"; import {createErrorModal} from "tc-shared/ui/elements/Modal"; import {spawnVideoViewerInfo} from "tc-shared/ui/modal/video-viewers/Controller"; - -const cssStyle = require("./Renderer.scss"); +import {guid} from "tc-shared/crypto/uid"; let videoIdIndex = 0; interface ClientVideoController { @@ -234,7 +230,12 @@ class RemoteClientVideoController implements ClientVideoController { if(!stream) { state = { state: "failed", reason: tr("Missing video stream") }; } else { - state = { state: "connected", stream: stream }; + const streamUuid = guid(); + const streamMap = getVideoStreamMap(); + streamMap[streamUuid] = stream; + setTimeout(() => delete streamMap[streamUuid], 60 * 1000); + + state = { state: "connected", streamObjectId: streamUuid }; } } diff --git a/shared/js/ui/frames/video/Definitions.ts b/shared/js/ui/frames/video/Definitions.ts index 9e094bf6..0a68f5a4 100644 --- a/shared/js/ui/frames/video/Definitions.ts +++ b/shared/js/ui/frames/video/Definitions.ts @@ -48,7 +48,7 @@ export type VideoStreamState = { reason?: string } | { state: "connected", - stream: MediaStream + streamObjectId: string }; export type VideoSubscribeInfo = { @@ -173,4 +173,15 @@ export function makeVideoAutoplay(video: HTMLVideoElement) : () => void { video.removeEventListener("pause", listenerPause); video.removeEventListener("ended", listenerEnded); }; +} + +const kVideoStreamMapName = "__teaspeak_video_streams__" + __build.timestamp + "_" + __build.version; +export function getVideoStreamMap() : { [key: string]: MediaStream } { + let windowInstance = window; + while(windowInstance.opener) { + /* Are we sure about this while loop? */ + windowInstance = windowInstance.opener; + } + + return windowInstance[kVideoStreamMapName] || (windowInstance[kVideoStreamMapName] = {}); } \ No newline at end of file diff --git a/shared/js/ui/frames/video/Renderer.tsx b/shared/js/ui/frames/video/Renderer.tsx index df60f96e..6658156e 100644 --- a/shared/js/ui/frames/video/Renderer.tsx +++ b/shared/js/ui/frames/video/Renderer.tsx @@ -5,7 +5,7 @@ import {ClientIcon} from "svg-sprites/client-icons"; import {Registry} from "tc-shared/events"; import { ChannelVideoEvents, ChannelVideoInfo, - ChannelVideoStreamState, + ChannelVideoStreamState, getVideoStreamMap, kLocalVideoId, makeVideoAutoplay, VideoStreamState, VideoSubscribeInfo @@ -269,7 +269,7 @@ const MediaStreamVideoRenderer = React.memo((props: { stream: MediaStream | unde ) }); -const VideoStreamPlayer = (props: { videoId: string, streamType: VideoBroadcastType, className?: string }) => { +const VideoStreamPlayer = React.memo((props: { videoId: string, streamType: VideoBroadcastType, className?: string }) => { const events = useContext(EventContext); const [ state, setState ] = useState(() => { events.fire("query_video_stream", { videoId: props.videoId, broadcastType: props.streamType }); @@ -301,9 +301,20 @@ const VideoStreamPlayer = (props: { videoId: string, streamType: VideoBroadcastT ); case "connected": + const streamMap = getVideoStreamMap(); + if(typeof streamMap[state.streamObjectId] === "undefined") { + return ( +
+
+ Missing stream object +
+
+ ); + } + return ( ); } -} +}); const VideoPlayer = React.memo((props: { videoId: string, cameraState: ChannelVideoStreamState, screenState: ChannelVideoStreamState }) => { const streamElements = []; diff --git a/shared/js/ui/react-elements/Helper.ts b/shared/js/ui/react-elements/Helper.ts index 10c17518..6b09e00a 100644 --- a/shared/js/ui/react-elements/Helper.ts +++ b/shared/js/ui/react-elements/Helper.ts @@ -1,5 +1,6 @@ import {Dispatch, SetStateAction, useEffect, useMemo, useState} from "react"; import {RegistryKey, RegistryValueType, settings, ValuedRegistryKey} from "tc-shared/settings"; +import {IpcRegistryDescription, Registry} from "tc-events"; export function useDependentState( factory: (prevState?: S) => S, @@ -42,4 +43,12 @@ export function useGlobalSetting(key, defaultValue) { useEffect(() => settings.globalChangeListener(key, value => setValue(value)), []); return value; +} + +export function useRegistry(description: IpcRegistryDescription | undefined) : Registry | undefined; +export function useRegistry(description: IpcRegistryDescription) : Registry +export function useRegistry(description) { + const events = useMemo(() => description ? Registry.fromIpcDescription(description) : undefined, [ description ]); + useEffect(() => () => events?.destroy(), [ description ]); + return events; } \ No newline at end of file diff --git a/web/app/WebWindowManager.ts b/web/app/WebWindowManager.ts index f946a50f..ef1bc2e1 100644 --- a/web/app/WebWindowManager.ts +++ b/web/app/WebWindowManager.ts @@ -150,6 +150,9 @@ export class WebWindowManager implements WindowManager { }); const features = { + /* TODO: Configureable and enabled by default! */ + noopener: "no", + status: "no", location: "no", toolbar: "no",