2020-09-28 07:37:48 +00:00
import { Registry } from "tc-shared/events" ;
import {
AwayState ,
Bookmark ,
ConnectionState ,
2020-11-07 12:16:07 +00:00
ControlBarEvents ,
ControlBarMode ,
HostButtonInfo ,
MicrophoneState ,
VideoCamaraState
2020-09-28 07:37:48 +00:00
} 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" ;
2020-09-30 18:28:30 +00:00
import { spawnContextMenu } from "tc-shared/ui/ContextMenu" ;
2020-09-28 07:37:48 +00:00
import { ClientIcon } from "svg-sprites/client-icons" ;
2020-11-07 12:16:07 +00:00
import { createErrorModal } from "tc-shared/ui/elements/Modal" ;
2020-09-28 07:37:48 +00:00
const cssStyle = require ( "./Renderer.scss" ) ;
const cssButtonStyle = require ( "./Button.scss" ) ;
const Events = React . createContext < Registry < ControlBarEvents > > ( undefined ) ;
const ModeContext = React . createContext < ControlBarMode > ( undefined ) ;
const ConnectButton = ( ) = > {
const events = useContext ( Events ) ;
const [ state , setState ] = useState < ConnectionState > ( ( ) = > {
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 (
< DropdownEntry key = { "connect-server" } icon = { "client-connect" } text = { < Translatable > Connect to a server < / Translatable > }
onClick = { ( ) = > events . fire ( "action_connection_connect" , { newTab : false } ) } / >
) ;
} else {
subentries . push (
< DropdownEntry key = { "disconnect-current-a" } icon = { "client-disconnect" } text = { < Translatable > Disconnect from current server < / Translatable > }
onClick = { ( ) = > events . fire ( "action_connection_disconnect" , { generally : false } ) } / >
) ;
}
if ( state . generallyConnected ) {
subentries . push (
< DropdownEntry key = { "disconnect-current-b" } icon = { "client-disconnect" } text = { < Translatable > Disconnect from all servers < / Translatable > }
onClick = { ( ) = > events . fire ( "action_connection_disconnect" , { generally : true } ) } / >
) ;
}
subentries . push (
< DropdownEntry key = { "connect-new-tab" } icon = { "client-connect" } text = { < Translatable > Connect to a server in another tab < / Translatable > }
onClick = { ( ) = > events . fire ( "action_connection_connect" , { newTab : true } ) } / >
) ;
}
if ( state ? . currentlyConnected ) {
return (
< Button colorTheme = { "default" } autoSwitch = { false } iconNormal = { "client-disconnect" } tooltip = { tr ( "Disconnect from server" ) }
onToggle = { ( ) = > events . fire ( "action_connection_disconnect" , { generally : false } ) } key = { "connected" } >
{ subentries }
< / Button >
) ;
} else {
return (
< Button colorTheme = { "default" } autoSwitch = { false } iconNormal = { "client-connect" } tooltip = { tr ( "Connect to a server" ) }
onToggle = { ( ) = > events . fire ( "action_connection_connect" , { newTab : false } ) } key = { "disconnected" } >
{ subentries }
< / Button >
) ;
}
} ;
const BookmarkRenderer = ( props : { bookmark : Bookmark , refButton : React.RefObject < Button > } ) = > {
const events = useContext ( Events ) ;
if ( typeof props . bookmark . children !== "undefined" ) {
return (
< DropdownEntry key = { props . bookmark . uniqueId } text = { props . bookmark . label } >
{ props . bookmark . children . map ( entry = > < BookmarkRenderer bookmark = { entry } key = { entry . uniqueId } refButton = { props . refButton } / > ) }
< / DropdownEntry >
) ;
} else {
return (
< DropdownEntry key = { props . bookmark . uniqueId }
icon = { props . bookmark . icon }
text = { props . bookmark . label }
onClick = { ( ) = > events . fire ( "action_bookmark_connect" , { bookmarkUniqueId : props.bookmark.uniqueId , newTab : false } ) }
onAuxClick = { event = > event . button === 1 && events . fire ( "action_bookmark_connect" , { bookmarkUniqueId : props.bookmark.uniqueId , newTab : true } ) }
onContextMenu = { event = > {
event . preventDefault ( ) ;
props . refButton . current ? . setState ( { dropdownForceShow : true } ) ;
spawnContextMenu ( { pageY : event.pageY , pageX : event.pageX } , [
{
type : "normal" ,
icon : ClientIcon.Connect ,
label : tr ( "Connect" ) ,
click : ( ) = > events . fire ( "action_bookmark_connect" , { bookmarkUniqueId : props.bookmark.uniqueId , newTab : false } )
} ,
{
type : "normal" ,
icon : ClientIcon.Connect ,
label : tr ( "Connect in a new tab" ) ,
click : ( ) = > events . fire ( "action_bookmark_connect" , { bookmarkUniqueId : props.bookmark.uniqueId , newTab : true } )
}
] , ( ) = > props . refButton . current ? . setState ( { dropdownForceShow : false } ) ) ;
} }
/ >
) ;
}
} ;
const BookmarkButton = ( ) = > {
const events = useContext ( Events ) ;
const mode = useContext ( ModeContext ) ;
const refButton = useRef < Button > ( ) ;
const [ bookmarks , setBookmarks ] = useState < Bookmark [ ] > ( ( ) = > {
events . fire ( "query_bookmarks" ) ;
return [ ] ;
} ) ;
events . reactUse ( "notify_bookmarks" , event = > setBookmarks ( event . marks . slice ( ) ) ) ;
let entries = [ ] ;
if ( mode === "main" ) {
entries . push (
< DropdownEntry icon = { "client-bookmark_manager" } text = { < Translatable > Manage bookmarks < / Translatable > }
onClick = { ( ) = > events . fire ( "action_bookmark_manage" ) } key = { "manage" } / >
) ;
entries . push (
< DropdownEntry icon = { "client-bookmark_add" } text = { < Translatable > Add current server to bookmarks < / Translatable > }
onClick = { ( ) = > events . fire ( "action_bookmark_add_current_server" ) } key = { "add" } / >
) ;
}
if ( bookmarks . length > 0 ) {
if ( entries . length > 0 ) {
entries . push ( < hr key = { "hr" } / > ) ;
}
entries . push ( . . . bookmarks . map ( mark = > < BookmarkRenderer key = { mark . uniqueId } bookmark = { mark } refButton = { refButton } / > ) ) ;
}
return (
< Button ref = { refButton } className = { cssButtonStyle . buttonBookmarks + " " + cssStyle . hideSmallPopout } autoSwitch = { false } iconNormal = { "client-bookmark_manager" } >
{ entries }
< / Button >
)
} ;
const AwayButton = ( ) = > {
const events = useContext ( Events ) ;
const [ state , setState ] = useState < AwayState > ( ( ) = > {
events . fire ( "query_away_state" ) ;
return undefined ;
} ) ;
events . on ( "notify_away_state" , event = > setState ( event . state ) ) ;
let dropdowns = [ ] ;
if ( state ? . locallyAway ) {
dropdowns . push ( < DropdownEntry key = { "cgo" } icon = { ClientIcon . Present } text = { < Translatable > Go online < / Translatable > }
onClick = { ( ) = > events . fire ( "action_toggle_away" , { away : false , globally : false } ) } / > ) ;
} else {
dropdowns . push ( < DropdownEntry key = { "sas" } icon = { ClientIcon . Away } text = { < Translatable > Set away on this server < / Translatable > }
onClick = { ( ) = > events . fire ( "action_toggle_away" , { away : true , globally : false } ) } / > ) ;
}
dropdowns . push ( < DropdownEntry key = { "sam" } icon = { ClientIcon . Away } text = { < Translatable > Set away message on this server < / Translatable > }
onClick = { ( ) = > events . fire ( "action_toggle_away" , { away : true , globally : false , promptMessage : true } ) } / > ) ;
dropdowns . push ( < hr key = { "-hr" } / > ) ;
if ( state ? . globallyAway !== "none" ) {
dropdowns . push ( < DropdownEntry key = { "goa" } icon = { ClientIcon . Present } text = { < Translatable > Go online for all servers < / Translatable > }
onClick = { ( ) = > events . fire ( "action_toggle_away" , { away : false , globally : true } ) } / > ) ;
}
if ( state ? . globallyAway !== "full" ) {
dropdowns . push ( < DropdownEntry key = { "saa" } icon = { ClientIcon . Away } text = { < Translatable > Set away on all servers < / Translatable > }
onClick = { ( ) = > events . fire ( "action_toggle_away" , { away : true , globally : true } ) } / > ) ;
}
dropdowns . push ( < DropdownEntry key = { "sama" } icon = { ClientIcon . Away } text = { < Translatable > Set away message for all servers < / Translatable > }
onClick = { ( ) = > events . fire ( "action_toggle_away" , { away : true , globally : true , promptMessage : true } ) } / > ) ;
return (
< Button
autoSwitch = { false }
switched = { ! ! state ? . locallyAway }
iconNormal = { ClientIcon . Away }
iconSwitched = { ClientIcon . Present }
onToggle = { target = > events . fire ( "action_toggle_away" , { away : target , globally : false } ) }
>
{ dropdowns }
< / Button >
) ;
} ;
2020-11-07 12:16:07 +00:00
const VideoButton = ( ) = > {
const events = useContext ( Events ) ;
const [ state , setState ] = useState < VideoCamaraState > ( ( ) = > {
events . fire ( "query_camara_state" ) ;
return "unsupported" ;
} ) ;
events . on ( "notify_camara_state" , event = > setState ( event . state ) ) ;
switch ( state ) {
case "unsupported" :
return < Button switched = { true } colorTheme = { "red" } autoSwitch = { false } iconNormal = { ClientIcon . VideoMuted } tooltip = { tr ( "Video broadcasting not supported" ) } key = { "unsupported" }
onToggle = { ( ) = > createErrorModal ( tr ( "Video broadcasting unsupported" ) , tr ( "Video broadcasting isn't supported by the target server." ) ) . open ( ) }
/ > ;
case "unavailable" :
return < Button switched = { true } colorTheme = { "red" } autoSwitch = { false } iconNormal = { ClientIcon . VideoMuted } tooltip = { tr ( "Video broadcasting not available" ) } key = { "unavailable" }
onToggle = { ( ) = > createErrorModal ( tr ( "Video broadcasting unavailable" ) , tr ( "Video broadcasting isn't available right now." ) ) . open ( ) } / > ;
case "disconnected" :
case "disabled" :
return < Button switched = { true } colorTheme = { "red" } autoSwitch = { false } iconNormal = { ClientIcon . VideoMuted }
onToggle = { ( ) = > events . fire ( "action_toggle_video" , { enable : true , broadcastType : "camera" } ) }
tooltip = { tr ( "Start video broadcasting" ) } key = { "enable" } / > ;
case "enabled" :
return < Button switched = { false } colorTheme = { "red" } autoSwitch = { false } iconNormal = { ClientIcon . VideoMuted }
onToggle = { ( ) = > events . fire ( "action_toggle_video" , { enable : false , broadcastType : "camera" } ) }
tooltip = { tr ( "Stop video broadcasting" ) } key = { "disable" } / > ;
}
}
2020-09-28 07:37:48 +00:00
const MicrophoneButton = ( ) = > {
const events = useContext ( Events ) ;
const [ state , setState ] = useState < MicrophoneState > ( ( ) = > {
events . fire ( "query_microphone_state" ) ;
return undefined ;
} ) ;
events . on ( "notify_microphone_state" , event = > setState ( event . state ) ) ;
if ( state === "muted" ) {
2020-11-07 12:16:07 +00:00
return < Button switched = { true } colorTheme = { "red" } autoSwitch = { false } iconNormal = { ClientIcon . InputMuted } tooltip = { tr ( "Unmute microphone" ) }
2020-09-28 07:37:48 +00:00
onToggle = { ( ) = > events . fire ( "action_toggle_microphone" , { enabled : true } ) } key = { "muted" } / > ;
} else if ( state === "enabled" ) {
2020-11-07 12:16:07 +00:00
return < Button colorTheme = { "red" } autoSwitch = { false } iconNormal = { ClientIcon . InputMuted } tooltip = { tr ( "Mute microphone" ) }
2020-09-28 07:37:48 +00:00
onToggle = { ( ) = > events . fire ( "action_toggle_microphone" , { enabled : false } ) } key = { "enabled" } / > ;
} else {
2020-11-07 12:16:07 +00:00
return < Button autoSwitch = { false } iconNormal = { ClientIcon . ActivateMicrophone } tooltip = { tr ( "Enable your microphone on this server" ) }
2020-09-28 07:37:48 +00:00
onToggle = { ( ) = > events . fire ( "action_toggle_microphone" , { enabled : true } ) } key = { "disabled" } / > ;
}
}
const SpeakerButton = ( ) = > {
const events = useContext ( Events ) ;
const [ enabled , setEnabled ] = useState < boolean > ( ( ) = > {
events . fire ( "query_speaker_state" ) ;
return true ;
} ) ;
events . on ( "notify_speaker_state" , event = > setEnabled ( event . enabled ) ) ;
if ( enabled ) {
return < Button colorTheme = { "red" } autoSwitch = { false } iconNormal = { ClientIcon . OutputMuted } tooltip = { tr ( "Mute headphones" ) }
onToggle = { ( ) = > events . fire ( "action_toggle_speaker" , { enabled : false } ) } key = { "enabled" } / > ;
} else {
return < Button switched = { true } colorTheme = { "red" } autoSwitch = { false } iconNormal = { ClientIcon . OutputMuted } tooltip = { tr ( "Unmute headphones" ) }
onToggle = { ( ) = > events . fire ( "action_toggle_speaker" , { enabled : true } ) } key = { "disabled" } / > ;
}
}
const SubscribeButton = ( ) = > {
const events = useContext ( Events ) ;
const [ subscribe , setSubscribe ] = useState < boolean > ( ( ) = > {
events . fire ( "query_subscribe_state" ) ;
return true ;
} ) ;
events . on ( "notify_subscribe_state" , event = > setSubscribe ( event . subscribe ) ) ;
return < Button switched = { subscribe }
autoSwitch = { false }
iconNormal = { ClientIcon . UnsubscribeFromAllChannels }
iconSwitched = { ClientIcon . SubscribeToAllChannels }
className = { cssStyle . hideSmallPopout }
onToggle = { flag = > events . fire ( "action_toggle_subscribe" , { subscribe : flag } ) }
/ > ;
}
const QueryButton = ( ) = > {
const events = useContext ( Events ) ;
const mode = useContext ( ModeContext ) ;
const [ shown , setShown ] = useState < boolean > ( ( ) = > {
events . fire ( "query_query_state" ) ;
return true ;
} ) ;
events . on ( "notify_query_state" , event = > setShown ( event . shown ) ) ;
if ( mode === "channel-popout" ) {
return (
< Button switched = { shown }
autoSwitch = { false }
iconNormal = { ClientIcon . ServerQuery }
className = { cssStyle . hideSmallPopout }
onToggle = { flag = > events . fire ( "action_toggle_query" , { show : flag } ) }
key = { "mode-channel-popout" }
/ >
) ;
} else {
let toggle ;
if ( shown ) {
toggle = < DropdownEntry key = { "query-show" } icon = { ClientIcon . ToggleServerQueryClients } text = { < Translatable > Hide server queries < / Translatable > }
onClick = { ( ) = > events . fire ( "action_toggle_query" , { show : false } ) } / > ;
} else {
toggle = < DropdownEntry key = { "query-hide" } icon = { ClientIcon . ToggleServerQueryClients } text = { < Translatable > Show server queries < / Translatable > }
onClick = { ( ) = > events . fire ( "action_toggle_query" , { show : true } ) } / > ;
}
return (
< Button switched = { shown }
autoSwitch = { false }
iconNormal = { ClientIcon . ServerQuery }
className = { cssStyle . hideSmallPopout }
onToggle = { flag = > events . fire ( "action_toggle_query" , { show : flag } ) }
key = { "mode-full" }
>
{ toggle }
< DropdownEntry icon = { ClientIcon . ServerQuery } text = { < Translatable > Manage server queries < / Translatable > }
2020-09-29 13:02:36 +00:00
onClick = { ( ) = > events . fire ( "action_query_manage" ) } key = { "manage-entries" } / >
2020-09-28 07:37:48 +00:00
< / Button >
) ;
}
} ;
const HostButton = ( ) = > {
const events = useContext ( Events ) ;
const [ hostButton , setHostButton ] = useState < HostButtonInfo > ( ( ) = > {
events . fire ( "query_host_button" ) ;
return undefined ;
} ) ;
events . reactUse ( "notify_host_button" , event = > setHostButton ( event . button ) ) ;
if ( ! hostButton ) {
return null ;
} else {
return (
< a
className = { cssButtonStyle . button + " " + cssButtonStyle . buttonHostbutton + " " + cssStyle . hideSmallPopout }
title = { hostButton . title || tr ( "Hostbutton" ) }
onClick = { event = > {
window . open ( hostButton . target || hostButton . url , '_blank' ) ;
event . preventDefault ( ) ;
} }
>
< img alt = { tr ( "Hostbutton" ) } src = { hostButton . url } / >
< / a >
) ;
}
} ;
export const ControlBar2 = ( props : { events : Registry < ControlBarEvents > , className? : string } ) = > {
const [ mode , setMode ] = useState < ControlBarMode > ( ( ) = > {
props . events . fire ( "query_mode" ) ;
return undefined ;
} ) ;
props . events . reactUse ( "notify_mode" , event = > setMode ( event . mode ) ) ;
const items = [ ] ;
if ( mode !== "channel-popout" ) {
items . push ( < ConnectButton key = { "connect" } / > ) ;
2020-09-29 13:02:36 +00:00
items . push ( < BookmarkButton key = { "bookmarks" } / > ) ;
items . push ( < div className = { cssStyle . divider + " " + cssStyle . hideSmallPopout } key = { "divider-1" } / > ) ;
2020-09-28 07:37:48 +00:00
}
items . push ( < AwayButton key = { "away" } / > ) ;
2020-11-07 12:16:07 +00:00
items . push ( < VideoButton key = { "video" } / > ) ;
2020-09-28 07:37:48 +00:00
items . push ( < MicrophoneButton key = { "microphone" } / > ) ;
items . push ( < SpeakerButton key = { "speaker" } / > ) ;
2020-09-29 13:02:36 +00:00
items . push ( < div className = { cssStyle . divider + " " + cssStyle . hideSmallPopout } key = { "divider-2" } / > ) ;
2020-09-28 07:37:48 +00:00
items . push ( < SubscribeButton key = { "subscribe" } / > ) ;
items . push ( < QueryButton key = { "query" } / > ) ;
2020-09-29 13:02:36 +00:00
items . push ( < div className = { cssStyle . spacer } key = { "spacer" } / > ) ;
2020-09-28 07:37:48 +00:00
items . push ( < HostButton key = { "hostbutton" } / > ) ;
return (
< Events.Provider value = { props . events } >
< ModeContext.Provider value = { mode } >
< div className = { cssStyle . controlBar + " " + cssStyle [ "mode-" + mode ] } >
{ items }
< / div >
< / ModeContext.Provider >
< / Events.Provider >
)
} ;