import {Registry} from "tc-shared/events"; import { AwayState, Bookmark, ConnectionState, ControlBarEvents, ControlBarMode, HostButtonInfo, MicrophoneDeviceInfo, MicrophoneState, VideoDeviceInfo, VideoState } from "tc-shared/ui/frames/control-bar/Definitions"; import * as React from "react"; import {useContext, useRef, useState} from "react"; import {DropdownEntry} from "tc-shared/ui/frames/control-bar/DropDown"; import {Translatable} from "tc-shared/ui/react-elements/i18n"; import {Button} from "tc-shared/ui/frames/control-bar/Button"; import {spawnContextMenu} from "tc-shared/ui/ContextMenu"; import {ClientIcon} from "svg-sprites/client-icons"; import {createErrorModal} from "tc-shared/ui/elements/Modal"; import {VideoBroadcastType} from "tc-shared/connection/VideoConnection"; import {Settings, settings} from "tc-shared/settings"; const cssStyle = require("./Renderer.scss"); const cssButtonStyle = require("./Button.scss"); const Events = React.createContext>(undefined); const ModeContext = React.createContext(undefined); const ConnectButton = () => { const events = useContext(Events); const [ state, setState ] = useState(() => { events.fire("query_connection_state"); return undefined; }); events.reactUse("notify_connection_state", event => setState(event.state)); let subentries = []; if(state?.multisession) { if(!state.currentlyConnected) { subentries.push( Connect to a server} onClick={() => events.fire("action_connection_connect", { newTab: false })} /> ); } else { subentries.push( Disconnect from current server} onClick={() => events.fire("action_connection_disconnect", { generally: false })} /> ); } if(state.generallyConnected) { subentries.push( Disconnect from all servers} onClick={() => events.fire("action_connection_disconnect", { generally: true })}/> ); } subentries.push( Connect to a server in another tab} onClick={() => events.fire("action_connection_connect", { newTab: true })} /> ); } if(state?.currentlyConnected) { return ( ); } else { return ( ); } }; const BookmarkRenderer = (props: { bookmark: Bookmark, refButton: React.RefObject ) }; const AwayButton = () => { const events = useContext(Events); const [ state, setState ] = useState(() => { events.fire("query_away_state"); return undefined; }); events.on("notify_away_state", event => setState(event.state)); let dropdowns = []; if(state?.locallyAway) { dropdowns.push(Go online} onClick={() => events.fire("action_toggle_away", { away: false, globally: false })} />); } else { dropdowns.push(Set away on this server} onClick={() => events.fire("action_toggle_away", { away: true, globally: false })} />); } dropdowns.push(Set away message on this server} onClick={() => events.fire("action_toggle_away", { away: true, globally: false, promptMessage: true })} />); dropdowns.push(
); if(state?.globallyAway !== "none") { dropdowns.push(Go online for all servers} onClick={() => events.fire("action_toggle_away", { away: false, globally: true })} />); } if(state?.globallyAway !== "full") { dropdowns.push(Set away on all servers} onClick={() => events.fire("action_toggle_away", { away: true, globally: true })} />); } dropdowns.push(Set away message for all servers} onClick={() => events.fire("action_toggle_away", { away: true, globally: true, promptMessage: true })} />); return ( ); }; const VideoDeviceList = React.memo(() => { const events = useContext(Events); const [ devices, setDevices ] = useState(() => { events.fire("query_camera_list"); return []; }); events.reactUse("notify_camera_list", event => setDevices(event.devices)); if(devices.length === 0) { return null; } return ( <>
{devices.map(device => ( events.fire("action_toggle_video", {enable: true, broadcastType: "camera", deviceId: device.id, quickStart: true})} /> ))} ); }); const VideoButton = (props: { type: VideoBroadcastType }) => { const events = useContext(Events); const [ state, setState ] = useState(() => { events.fire("query_video_state", { broadcastType: props.type }); return "unsupported"; }); events.on("notify_video_state", event => event.broadcastType === props.type && setState(event.state)); let icon: ClientIcon = props.type === "camera" ? ClientIcon.VideoMuted : ClientIcon.ShareScreen; switch (state) { case "unsupported": { let tooltip = props.type === "camera" ? tr("Video broadcasting not supported") : tr("Screen sharing not supported"); let modalTitle = props.type === "camera" ? tr("Video broadcasting unsupported") : tr("Screen sharing unsupported"); let modalBody = props.type === "camera" ? tr("Video broadcasting isn't supported by the target server.") : tr("Screen sharing isn't supported by the target server."); let dropdownText = props.type === "camera" ? tr("Start video broadcasting") : tr("Start screen sharing"); return ( ); } case "unavailable": { let tooltip = props.type === "camera" ? tr("Video broadcasting not available") : tr("Screen sharing not available"); let modalTitle = props.type === "camera" ? tr("Video broadcasting unavailable") : tr("Screen sharing unavailable"); let modalBody = props.type === "camera" ? tr("Video broadcasting isn't available right now.") : tr("Screen sharing isn't available right now."); let dropdownText = props.type === "camera" ? tr("Start video broadcasting") : tr("Start screen sharing"); return ( ); } case "disconnected": case "disabled": { let tooltip = props.type === "camera" ? tr("Start video broadcasting") : tr("Start screen sharing"); let dropdownText = props.type === "camera" ? tr("Start video broadcasting") : tr("Start screen sharing"); return ( ); } case "enabled": { let tooltip = props.type === "camera" ? tr("Stop video broadcasting") : tr("Stop screen sharing"); let dropdownTextManage = props.type === "camera" ? tr("Configure/change video broadcasting") : tr("Configure/change screen sharing"); let dropdownTextStop = props.type === "camera" ? tr("Stop video broadcasting") : tr("Stop screen sharing"); return ( ); } } } const MicrophoneButton = () => { const events = useContext(Events); const [ state, setState ] = useState(() => { events.fire("query_microphone_state"); return undefined; }); events.on("notify_microphone_state", event => setState(event.state)); if(state === "muted") { return ( ); } else if(state === "enabled") { return ( ); } else { return ( ); } } /* This should be above all driver weights */ const kDriverWeightSelected = 1000; const kDriverWeights = { "MME": 100, "Windows DirectSound": 80, "Windows WASAPI": 50 }; const MicrophoneDeviceList = React.memo(() => { const events = useContext(Events); const [ deviceList, setDeviceList ] = useState(() => { events.fire("query_microphone_list"); return []; }); events.reactUse("notify_microphone_list", event => setDeviceList(event.devices)); if(deviceList.length <= 1) { /* we don't need a select here */ return null; } const devices: {[key: string]: { weight: number, device: MicrophoneDeviceInfo }} = {}; for(const entry of deviceList) { const weight = entry.selected ? kDriverWeightSelected : (kDriverWeights[entry.driver] | 0); if(typeof devices[entry.name] !== "undefined" && devices[entry.name].weight >= weight) { continue; } devices[entry.name] = { weight, device: entry } } return ( <>
{Object.values(devices).map(({ device }) => ( events.fire("action_toggle_microphone", { enabled: true, targetDeviceId: device.id })} /> ))} ); }); const SpeakerButton = () => { const events = useContext(Events); const [ enabled, setEnabled ] = useState(() => { events.fire("query_speaker_state"); return true; }); events.on("notify_speaker_state", event => setEnabled(event.enabled)); if(enabled) { return ); } }; const HostButton = () => { const events = useContext(Events); const [ hostButton, setHostButton ] = useState(() => { events.fire("query_host_button"); return undefined; }); events.reactUse("notify_host_button", event => setHostButton(event.button)); if(!hostButton) { return null; } else { return ( { window.open(hostButton.target || hostButton.url, '_blank'); event.preventDefault(); }} > {tr("Hostbutton")} ); } }; export const ControlBar2 = (props: { events: Registry, className?: string }) => { const [ mode, setMode ] = useState(() => { props.events.fire("query_mode"); return undefined; }); props.events.reactUse("notify_mode", event => setMode(event.mode)); const items = []; if(mode !== "channel-popout") { items.push(); items.push(); items.push(
); } items.push(); items.push(); items.push(); items.push(); items.push(
); items.push(); items.push(); items.push(); items.push(
); items.push(); return (
{items}
) };