/// /// /// /* client_output_hardware Value: '1' client_output_muted Value: '0' client_outputonly_muted Value: '0' client_input_hardware Value: '1' client_input_muted Value: '0' client_away Value: '0' client_away_message Value: '' */ let control_bar: ControlBar; /* global variable to access the control bar */ type MicrophoneState = "disabled" | "muted" | "enabled"; type HeadphoneState = "muted" | "enabled"; type AwayState = "away-global" | "away" | "online"; class ControlBar { private _button_away_active: AwayState; private _button_microphone: MicrophoneState; private _button_speakers: HeadphoneState; private _button_subscribe_all: boolean; private _button_query_visible: boolean; private connection_handler: ConnectionHandler | undefined; private _button_hostbanner: JQuery; htmlTag: JQuery; constructor(htmlTag: JQuery) { this.htmlTag = htmlTag; } initialize_connection_handler_state(handler?: ConnectionHandler) { /* setup the state like the last displayed one */ handler.client_status.output_muted = this._button_speakers === "muted"; handler.client_status.input_muted = this._button_microphone === "muted"; handler.client_status.channel_subscribe_all = this._button_subscribe_all; handler.client_status.queries_visible = this._button_query_visible; } set_connection_handler(handler?: ConnectionHandler) { if(this.connection_handler == handler) return; this.connection_handler = handler; this.apply_server_state(); this.update_connection_state(); } apply_server_state() { if(!this.connection_handler) return; const flag_away = typeof(this.connection_handler.client_status.away) === "string" || this.connection_handler.client_status.away; if(!flag_away) this.button_away_active = "online"; else if(flag_away && this._button_away_active === "online") this.button_away_active = "away"; this.button_query_visible = this.connection_handler.client_status.queries_visible; this.button_subscribe_all = this.connection_handler.client_status.channel_subscribe_all; this.apply_server_hostbutton(); this.apply_server_voice_state(); } apply_server_hostbutton() { const server = this.connection_handler.channelTree.server; if(server && server.properties.virtualserver_hostbutton_gfx_url) { this._button_hostbanner .attr("title", server.properties.virtualserver_hostbutton_tooltip || server.properties.virtualserver_hostbutton_gfx_url) .attr("href", server.properties.virtualserver_hostbutton_url); this._button_hostbanner.find("img").attr("src", server.properties.virtualserver_hostbutton_gfx_url); this._button_hostbanner.each((_, e) => { e.style.display = null; }); } else { this._button_hostbanner.each((_, e) => { e.style.display = "none"; }); } } apply_server_voice_state() { if(!this.connection_handler) return; this.button_microphone = !this.connection_handler.client_status.input_hardware ? "disabled" : this.connection_handler.client_status.input_muted ? "muted" : "enabled"; this.button_speaker = this.connection_handler.client_status.output_muted ? "muted" : "enabled"; top_menu.update_state(); //TODO: Only run "small" update? } current_connection_handler() { return this.connection_handler; } initialise() { let dropdownify = (tag: JQuery) => { tag.find(".dropdown-arrow").on('click', () => { tag.addClass("displayed"); }).hover(() => { tag.addClass("displayed"); }, () => { if(tag.find(".dropdown:hover").length > 0) return; tag.removeClass("displayed"); }); tag.on('mouseleave', () => { tag.removeClass("displayed"); }); }; this.htmlTag.find(".btn_connect").on('click', this.on_open_connect.bind(this)); this.htmlTag.find(".btn_connect_new_tab").on('click', this.on_open_connect_new_tab.bind(this)); this.htmlTag.find(".btn_disconnect").on('click', this.on_execute_disconnect.bind(this)); this.htmlTag.find(".btn_mute_input").on('click', this.on_toggle_microphone.bind(this)); this.htmlTag.find(".btn_mute_output").on('click', this.on_toggle_sound.bind(this)); this.htmlTag.find(".button-subscribe-mode").on('click', this.on_toggle_channel_subscribe.bind(this)); this.htmlTag.find(".btn_query_toggle").on('click', this.on_toggle_query_view.bind(this)); this.htmlTag.find(".btn_open_settings").on('click', this.on_open_settings.bind(this)); this.htmlTag.find(".btn_permissions").on('click', this.on_open_permissions.bind(this)); this.htmlTag.find(".btn_banlist").on('click', this.on_open_banslist.bind(this)); this.htmlTag.find(".button-playlist-manage").on('click', this.on_open_playlist_manage.bind(this)); this.htmlTag.find(".btn_token_use").on('click', this.on_token_use.bind(this)); this.htmlTag.find(".btn_token_list").on('click', this.on_token_list.bind(this)); (this._button_hostbanner = this.htmlTag.find(".button-hostbutton")).hide().on('click', () => { if(!this.connection_handler) return; const server = this.connection_handler.channelTree.server; if(!server || !server.properties.virtualserver_hostbutton_url) return; window.open(server.properties.virtualserver_hostbutton_url, '_blank'); }); { this.htmlTag.find(".btn_away_disable").on('click', this.on_away_disable.bind(this)); this.htmlTag.find(".btn_away_disable_global").on('click', this.on_away_disable_global.bind(this)); this.htmlTag.find(".btn_away_enable").on('click', this.on_away_enable.bind(this)); this.htmlTag.find(".btn_away_enable_global").on('click', this.on_away_enable_global.bind(this)); this.htmlTag.find(".btn_away_message").on('click', this.on_away_set_message.bind(this)); this.htmlTag.find(".btn_away_message_global").on('click', this.on_away_set_message_global.bind(this)); this.htmlTag.find(".btn_away_toggle").on('click', this.on_away_toggle.bind(this)); } dropdownify(this.htmlTag.find(".container-connect")); dropdownify(this.htmlTag.find(".container-disconnect")); dropdownify(this.htmlTag.find(".btn_token")); dropdownify(this.htmlTag.find(".btn_away")); dropdownify(this.htmlTag.find(".btn_bookmark")); dropdownify(this.htmlTag.find(".btn_query")); dropdownify(this.htmlTag.find(".dropdown-audio")); dropdownify(this.htmlTag.find(".dropdown-servertools")); { } { this.htmlTag.find(".btn_bookmark_list").on('click', this.on_bookmark_manage.bind(this)); this.htmlTag.find(".btn_bookmark_add").on('click', this.on_bookmark_server_add.bind(this)); } { /* search for query buttons not only on the large device button */ this.htmlTag.find(".btn_query_create").on('click', this.on_open_query_create.bind(this)); this.htmlTag.find(".btn_query_manage").on('click', this.on_open_query_manage.bind(this)); } this.update_bookmarks(); this.update_bookmark_status(); //Need an initialise this.button_speaker = settings.static_global(Settings.KEY_CONTROL_MUTE_OUTPUT, false) ? "muted" : "enabled"; this.button_microphone = settings.static_global(Settings.KEY_CONTROL_MUTE_INPUT, false) ? "muted" : "enabled"; this.button_subscribe_all = true; this.button_query_visible = false; } /* Update the UI */ set button_away_active(flag: AwayState) { if(this._button_away_active === flag) return; this._button_away_active = flag; this.update_button_away(); } update_button_away() { const button_away_enable = this.htmlTag.find(".btn_away_enable"); const button_away_disable = this.htmlTag.find(".btn_away_disable"); const button_away_toggle = this.htmlTag.find(".btn_away_toggle"); const button_away_disable_global = this.htmlTag.find(".btn_away_disable_global"); const button_away_enable_global = this.htmlTag.find(".btn_away_enable_global"); const button_away_message_global = this.htmlTag.find(".btn_away_message_global"); button_away_toggle.toggleClass("activated", this._button_away_active !== "online"); button_away_enable.toggle(this._button_away_active === "online"); button_away_disable.toggle(this._button_away_active !== "online"); const connections = server_connections.server_connection_handlers(); if(connections.length <= 1) { button_away_disable_global.hide(); button_away_enable_global.hide(); button_away_message_global.hide(); } else { button_away_message_global.show(); button_away_enable_global.toggle(server_connections.server_connection_handlers().filter(e => !e.client_status.away).length > 0); button_away_disable_global.toggle( this._button_away_active === "away-global" || server_connections.server_connection_handlers().filter(e => typeof(e.client_status.away) === "string" || e.client_status.away).length > 0 ) } } set button_microphone(state: MicrophoneState) { if(this._button_microphone === state) return; this._button_microphone = state; let tag = this.htmlTag.find(".btn_mute_input"); const tag_icon = tag.find(".icon_em, .icon"); tag.toggleClass('activated', state === "muted"); /* tag_icon .toggleClass('client-input_muted', state === "muted") .toggleClass('client-capture', state === "enabled") .toggleClass('client-activate_microphone', state === "disabled"); */ tag_icon .toggleClass('client-input_muted', state !== "disabled") .toggleClass('client-capture', false) .toggleClass('client-activate_microphone', state === "disabled"); if(state === "disabled") tag_icon.attr('title', tr("Enable your microphone on this server")); else if(state === "enabled") tag_icon.attr('title', tr("Mute microphone")); else tag_icon.attr('title', tr("Unmute microphone")); } set button_speaker(state: HeadphoneState) { if(this._button_speakers === state) return; this._button_speakers = state; let tag = this.htmlTag.find(".btn_mute_output"); const tag_icon = tag.find(".icon_em, .icon"); tag.toggleClass('activated', state === "muted"); /* tag_icon .toggleClass('client-output_muted', state !== "enabled") .toggleClass('client-volume', state === "enabled"); */ tag_icon .toggleClass('client-output_muted', true) .toggleClass('client-volume', false); if(state === "enabled") tag_icon.attr('title', tr("Mute sound")); else tag_icon.attr('title', tr("Unmute sound")); } set button_subscribe_all(state: boolean) { if(this._button_subscribe_all === state) return; this._button_subscribe_all = state; this.htmlTag .find(".button-subscribe-mode") .toggleClass('activated', this._button_subscribe_all) .find('.icon_em') .toggleClass('client-unsubscribe_from_all_channels', !this._button_subscribe_all) .toggleClass('client-subscribe_to_all_channels', this._button_subscribe_all); } set button_query_visible(state: boolean) { if(this._button_query_visible === state) return; this._button_query_visible = state; const button = this.htmlTag.find(".btn_query_toggle"); button.toggleClass('activated', this._button_query_visible); if(this._button_query_visible) button.find(".query-text").text(tr("Hide server queries")); else button.find(".query-text").text(tr("Show server queries")); } /* UI listener */ private on_away_toggle() { if(this._button_away_active === "away" || this._button_away_active === "away-global") this.button_away_active = "online"; else this.button_away_active = "away"; if(this.connection_handler) this.connection_handler.set_away_status(this._button_away_active !== "online"); } private on_away_enable() { this.button_away_active = "away"; if(this.connection_handler) this.connection_handler.set_away_status(true); } private on_away_disable() { this.button_away_active = "online"; if(this.connection_handler) this.connection_handler.set_away_status(false); } private on_away_set_message() { createInputModal(tr("Set away message"), tr("Please enter your away message"), message => true, message => { if(typeof(message) === "string") { this.button_away_active = "away"; if(this.connection_handler) this.connection_handler.set_away_status(message); } }).open(); } private on_away_enable_global() { this.button_away_active = "away-global"; for(const connection of server_connections.server_connection_handlers()) connection.set_away_status(true); } private on_away_disable_global() { this.button_away_active = "online"; for(const connection of server_connections.server_connection_handlers()) connection.set_away_status(false); } private on_away_set_message_global() { createInputModal(tr("Set global away message"), tr("Please enter your global away message"), message => true, message => { if(typeof(message) === "string") { this.button_away_active = "away"; for(const connection of server_connections.server_connection_handlers()) connection.set_away_status(message); } }).open(); } private on_toggle_microphone() { if(this._button_microphone === "disabled" || this._button_microphone === "muted") { this.button_microphone = "enabled"; sound.manager.play(Sound.MICROPHONE_ACTIVATED); } else { this.button_microphone = "muted"; sound.manager.play(Sound.MICROPHONE_MUTED); } if(this.connection_handler) { this.connection_handler.client_status.input_muted = this._button_microphone !== "enabled"; if(!this.connection_handler.client_status.input_hardware) this.connection_handler.acquire_recorder(default_recorder, true); /* acquire_recorder already updates the voice status */ else this.connection_handler.update_voice_status(undefined); /* just update the last changed value */ settings.changeGlobal(Settings.KEY_CONTROL_MUTE_INPUT, this.connection_handler.client_status.input_muted) } } private on_toggle_sound() { if(this._button_speakers === "muted") { this.button_speaker = "enabled"; sound.manager.play(Sound.SOUND_ACTIVATED); } else { this.button_speaker = "muted"; sound.manager.play(Sound.SOUND_MUTED); } if(this.connection_handler) { this.connection_handler.client_status.output_muted = this._button_speakers !== "enabled"; this.connection_handler.update_voice_status(undefined); /* just update the last changed value */ settings.changeGlobal(Settings.KEY_CONTROL_MUTE_OUTPUT, this.connection_handler.client_status.output_muted) } } private on_toggle_channel_subscribe() { this.button_subscribe_all = !this._button_subscribe_all; if(this.connection_handler) { this.connection_handler.client_status.channel_subscribe_all = this._button_subscribe_all; if(this._button_subscribe_all) this.connection_handler.channelTree.subscribe_all_channels(); else this.connection_handler.channelTree.unsubscribe_all_channels(true); this.connection_handler.settings.changeServer(Settings.KEY_CONTROL_CHANNEL_SUBSCRIBE_ALL, this._button_subscribe_all); } } private on_toggle_query_view() { this.button_query_visible = !this._button_query_visible; if(this.connection_handler) { this.connection_handler.client_status.queries_visible = this._button_query_visible; this.connection_handler.channelTree.toggle_server_queries(this._button_query_visible); this.connection_handler.settings.changeServer(Settings.KEY_CONTROL_SHOW_QUERIES, this._button_subscribe_all); } } private on_open_settings() { Modals.spawnSettingsModal(); } private on_open_connect() { if(this.connection_handler) this.connection_handler.cancel_reconnect(true); Modals.spawnConnectModal({}, { url: "ts.TeaSpeak.de", enforce: false }); } private on_open_connect_new_tab() { Modals.spawnConnectModal({ default_connect_new_tab: true }, { url: "ts.TeaSpeak.de", enforce: false }); } update_connection_state() { if(this.connection_handler.serverConnection && this.connection_handler.serverConnection.connected()) { this.htmlTag.find(".container-disconnect").show(); this.htmlTag.find(".container-connect").hide(); } else { this.htmlTag.find(".container-disconnect").hide(); this.htmlTag.find(".container-connect").show(); } /* switch (this.connection_handler.serverConnection ? this.connection_handler.serverConnection.connected() : ConnectionState.UNCONNECTED) { case ConnectionState.CONNECTED: case ConnectionState.CONNECTING: case ConnectionState.INITIALISING: this.htmlTag.find(".container-disconnect").show(); this.htmlTag.find(".container-connect").hide(); break; default: this.htmlTag.find(".container-disconnect").hide(); this.htmlTag.find(".container-connect").show(); } */ } private on_execute_disconnect() { this.connection_handler.cancel_reconnect(true); this.connection_handler.handleDisconnect(DisconnectReason.REQUESTED); //TODO message? this.update_connection_state(); this.connection_handler.sound.play(Sound.CONNECTION_DISCONNECTED); this.connection_handler.log.log(log.server.Type.DISCONNECTED, {}); } private on_token_use() { createInputModal(tr("Use token"), tr("Please enter your token/privilege key"), message => message.length > 0, result => { if(!result) return; if(this.connection_handler.serverConnection.connected) this.connection_handler.serverConnection.send_command("tokenuse", { token: result }).then(() => { createInfoModal(tr("Use token"), tr("Toke successfully used!")).open(); }).catch(error => { //TODO tr createErrorModal(tr("Use token"), MessageHelper.formatMessage(tr("Failed to use token: {}"), error instanceof CommandResult ? error.message : error)).open(); }); }).open(); } private on_token_list() { createErrorModal(tr("Not implemented"), tr("Token list is not implemented yet!")).open(); } private on_open_permissions() { let button = this.htmlTag.find(".btn_permissions"); button.addClass("activated"); setTimeout(() => { if(this.connection_handler) Modals.spawnPermissionEdit(this.connection_handler).open(); else createErrorModal(tr("You have to be connected"), tr("You have to be connected!")).open(); button.removeClass("activated"); }, 0); } private on_open_banslist() { if(!this.connection_handler.serverConnection) return; if(this.connection_handler.permissions.neededPermission(PermissionType.B_CLIENT_BAN_LIST).granted(1)) { Modals.openBanList(this.connection_handler); } else { createErrorModal(tr("You dont have the permission"), tr("You dont have the permission to view the ban list")).open(); this.connection_handler.sound.play(Sound.ERROR_INSUFFICIENT_PERMISSIONS); } } private on_bookmark_server_add() { bookmarks.add_current_server(); } update_bookmark_status() { this.htmlTag.find(".btn_bookmark_add").removeClass("hidden").addClass("disabled"); this.htmlTag.find(".btn_bookmark_remove").addClass("hidden"); } update_bookmarks() { // let tag_bookmark = this.htmlTag.find(".btn_bookmark > .dropdown"); tag_bookmark.find(".bookmark, .directory").remove(); const build_entry = (bookmark: bookmarks.DirectoryBookmark | bookmarks.Bookmark) => { if(bookmark.type == bookmarks.BookmarkType.ENTRY) { const mark = bookmark; const bookmark_connect = (new_tab: boolean) => { this.htmlTag.find(".btn_bookmark").find(".dropdown").removeClass("displayed"); //FIXME Not working bookmarks.boorkmak_connect(mark, new_tab); }; return $.spawn("div") .addClass("bookmark") .append( //$.spawn("div").addClass("icon client-server") IconManager.generate_tag(IconManager.load_cached_icon(mark.last_icon_id || 0), {animate: false}) /* must be false */ ) .append( $.spawn("div") .addClass("name") .text(bookmark.display_name) .on('click', event => { if(event.isDefaultPrevented()) return; bookmark_connect(false); }) .on('contextmenu', event => { if(event.isDefaultPrevented()) return; event.preventDefault(); contextmenu.spawn_context_menu(event.pageX, event.pageY, { type: contextmenu.MenuEntryType.ENTRY, name: tr("Connect"), icon_class: 'client-connect', callback: () => bookmark_connect(false) }, { type: contextmenu.MenuEntryType.ENTRY, name: tr("Connect in a new tab"), icon_class: 'client-connect', callback: () => bookmark_connect(true), visible: !settings.static_global(Settings.KEY_DISABLE_MULTI_SESSION) }, contextmenu.Entry.CLOSE(() => { setTimeout(() => { this.htmlTag.find(".btn_bookmark.dropdown-arrow").removeClass("force-show") }, 250); })); this.htmlTag.find(".btn_bookmark.dropdown-arrow").addClass("force-show"); }) ) } else { const mark = bookmark; const container = $.spawn("div").addClass("sub-menu dropdown"); const result = $.spawn("div") .addClass("directory") .append( $.spawn("div").addClass("icon client-folder") ) .append( $.spawn("div") .addClass("name") .text(bookmark.display_name) ) .append( $.spawn("div").addClass("arrow right") ) .append( $.spawn("div").addClass("sub-container") .append(container) ); /* we've to keep it this order because we're then keeping the reference of the loading icons... */ for(const member of mark.content) container.append(build_entry(member)); return result; } }; for(const bookmark of bookmarks.bookmarks().content) { const entry = build_entry(bookmark); tag_bookmark.append(entry); } } private on_bookmark_manage() { Modals.spawnBookmarkModal(); } private on_open_query_create() { if(this.connection_handler.permissions.neededPermission(PermissionType.B_CLIENT_CREATE_MODIFY_SERVERQUERY_LOGIN).granted(1)) { Modals.spawnQueryCreate(this.connection_handler); } else { createErrorModal(tr("You dont have the permission"), tr("You dont have the permission to create a server query login")).open(); this.connection_handler.sound.play(Sound.ERROR_INSUFFICIENT_PERMISSIONS); } } private on_open_query_manage() { if(this.connection_handler && this.connection_handler.connected) { Modals.spawnQueryManage(this.connection_handler); } else { createErrorModal(tr("You have to be connected"), tr("You have to be connected!")).open(); } } private on_open_playlist_manage() { if(this.connection_handler && this.connection_handler.connected) { Modals.spawnPlaylistManage(this.connection_handler); } else { createErrorModal(tr("You have to be connected"), tr("You have to be connected to use this function!")).open(); } } }