/* the bar on the right with the chats (Channel & Client) */ import {ClientEntry, MusicClientEntry} from "../../tree/Client"; import {ConnectionHandler} from "../../ConnectionHandler"; import {ChannelEntry} from "../../tree/Channel"; import {ServerEntry} from "../../tree/Server"; import {openMusicManage} from "../../ui/modal/ModalMusicManage"; import {formatMessage} from "../../ui/frames/chat"; import {ClientInfo} from "../../ui/frames/side/client_info"; import {MusicInfo} from "../../ui/frames/side/music_info"; import {ConversationManager} from "../../ui/frames/side/ConversationManager"; import {PrivateConversationManager} from "../../ui/frames/side/PrivateConversationManager"; import {generateIconJQueryTag, getIconManager} from "tc-shared/file/Icons"; import { tr } from "tc-shared/i18n/localize"; export enum InfoFrameMode { NONE = "none", CHANNEL_CHAT = "channel_chat", PRIVATE_CHAT = "private_chat", CLIENT_INFO = "client_info", MUSIC_BOT = "music_bot" } export class InfoFrame { private readonly handle: Frame; private _html_tag: JQuery; private _mode: InfoFrameMode; private _value_ping: JQuery; private _ping_updater: number; private _channel_text: ChannelEntry; private _channel_voice: ChannelEntry; private _button_conversation: HTMLElement; private _button_bot_manage: JQuery; private _button_song_add: JQuery; constructor(handle: Frame) { this.handle = handle; this._build_html_tag(); this.update_channel_talk(); this.update_channel_text(); this.set_mode(InfoFrameMode.CHANNEL_CHAT); this._ping_updater = setInterval(() => this.update_ping(), 2000); this.update_ping(); } html_tag() : JQuery { return this._html_tag; } destroy() { clearInterval(this._ping_updater); this._html_tag && this._html_tag.remove(); this._html_tag = undefined; this._value_ping = undefined; } private _build_html_tag() { this._html_tag = $("#tmpl_frame_chat_info").renderTag(); this._html_tag.find(".button-switch-chat-channel").on('click', () => this.handle.show_channel_conversations()); this._value_ping = this._html_tag.find(".value-ping"); this._html_tag.find(".chat-counter").on('click', event => this.handle.show_private_conversations()); this._button_conversation = this._html_tag.find(".button.open-conversation").on('click', event => { const selected_client = this.handle.client_info().current_client(); if(!selected_client) return; const conversation = selected_client ? this.handle.private_conversations().findOrCreateConversation(selected_client) : undefined; if(!conversation) return; this.handle.private_conversations().setActiveConversation(conversation); this.handle.show_private_conversations(); })[0]; this._button_bot_manage = this._html_tag.find(".bot-manage").on('click', event => { const bot = this.handle.music_info().current_bot(); if(!bot) return; openMusicManage(this.handle.handle, bot); }); this._button_song_add = this._html_tag.find(".bot-add-song").on('click', event => { this.handle.music_info().events.fire("action_song_add"); }); } update_ping() { this._value_ping.removeClass("very-good good medium poor very-poor"); const connection = this.handle.handle.serverConnection; if(!this.handle.handle.connected || !connection) { this._value_ping.text("Not connected"); return; } const ping = connection.ping(); if(!ping || typeof(ping.native) !== "number") { this._value_ping.text("Not available"); return; } let value; if(typeof(ping.javascript) !== "undefined") { value = ping.javascript; this._value_ping.text(ping.javascript.toFixed(0) + "ms").attr('title', 'Native: ' + ping.native.toFixed(3) + "ms \nJavascript: " + ping.javascript.toFixed(3) + "ms"); } else { value = ping.native; this._value_ping.text(ping.native.toFixed(0) + "ms").attr('title', "Ping: " + ping.native.toFixed(3) + "ms"); } if(value <= 10) this._value_ping.addClass("very-good"); else if(value <= 30) this._value_ping.addClass("good"); else if(value <= 60) this._value_ping.addClass("medium"); else if(value <= 150) this._value_ping.addClass("poor"); else this._value_ping.addClass("very-poor"); } update_channel_talk() { const client = this.handle.handle.getClient(); const channel = client ? client.currentChannel() : undefined; this._channel_voice = channel; const html_tag = this._html_tag.find(".value-voice-channel"); const html_limit_tag = this._html_tag.find(".value-voice-limit"); html_limit_tag.text(""); html_tag.children().remove(); if(channel) { if(channel.properties.channel_icon_id != 0) { const connection = channel.channelTree.client; generateIconJQueryTag(getIconManager().resolveIcon(channel.properties.channel_icon_id, connection.getCurrentServerUniqueId(), connection.handlerId)).appendTo(html_tag); } $.spawn("div").text(channel.formattedChannelName()).appendTo(html_tag); this.update_channel_limit(channel, html_limit_tag); } else { $.spawn("div").text("Not connected").appendTo(html_tag); } } update_channel_text() { const channel_tree = this.handle.handle.connected ? this.handle.handle.channelTree : undefined; const current_channel_id = channel_tree ? this.handle.channel_conversations().selectedConversation() : 0; const channel = channel_tree ? channel_tree.findChannel(current_channel_id) : undefined; this._channel_text = channel; const tag_container = this._html_tag.find(".mode-channel_chat.channel"); const html_tag_title = tag_container.find(".title"); const html_tag = tag_container.find(".value-text-channel"); const html_limit_tag = tag_container.find(".value-text-limit"); /* reset */ html_tag_title.text(tr("You're chatting in Channel")); html_limit_tag.text(""); html_tag.children().detach(); /* initialize */ if(channel) { if(channel.properties.channel_icon_id != 0) { const connection = channel.channelTree.client; generateIconJQueryTag(getIconManager().resolveIcon(channel.properties.channel_icon_id, connection.getCurrentServerUniqueId(), connection.handlerId)).appendTo(html_tag); } $.spawn("div").text(channel.formattedChannelName()).appendTo(html_tag); this.update_channel_limit(channel, html_limit_tag); } else if(channel_tree && current_channel_id > 0) { html_tag.append(formatMessage(tr("Unknown channel id {}"), current_channel_id)); } else if(channel_tree && current_channel_id == 0) { const server = this.handle.handle.channelTree.server; if(server.properties.virtualserver_icon_id != 0) { const connection = server.channelTree.client; generateIconJQueryTag(getIconManager().resolveIcon(server.properties.virtualserver_icon_id, connection.getCurrentServerUniqueId(), connection.handlerId)).appendTo(html_tag); } $.spawn("div").text(server.properties.virtualserver_name).appendTo(html_tag); html_tag_title.text(tr("You're chatting in Server")); this.update_server_limit(server, html_limit_tag); } else if(this.handle.handle.connected) { $.spawn("div").text("No channel selected").appendTo(html_tag); } else { $.spawn("div").text("Not connected").appendTo(html_tag); } } update_channel_client_count(channel: ChannelEntry) { if(channel === this._channel_text) { this.update_channel_limit(channel, this._html_tag.find(".value-text-limit")); } if(channel === this._channel_voice) { this.update_channel_limit(channel, this._html_tag.find(".value-voice-limit")); } } private update_channel_limit(channel: ChannelEntry, tag: JQuery) { let channel_limit = tr("Unlimited"); if(!channel.properties.channel_flag_maxclients_unlimited) channel_limit = "" + channel.properties.channel_maxclients; else if(!channel.properties.channel_flag_maxfamilyclients_unlimited) { if(channel.properties.channel_maxfamilyclients >= 0) channel_limit = "" + channel.properties.channel_maxfamilyclients; } tag.text(channel.clients(false).length + " / " + channel_limit); } private update_server_limit(server: ServerEntry, tag: JQuery) { const fn = () => { let text = server.properties.virtualserver_clientsonline + " / " + server.properties.virtualserver_maxclients; if(server.properties.virtualserver_reserved_slots) text += " (" + server.properties.virtualserver_reserved_slots + " " + tr("Reserved") + ")"; tag.text(text); }; server.updateProperties().then(fn).catch(error => tag.text(tr("Failed to update info"))); fn(); } update_chat_counter() { const privateConversations = this.handle.private_conversations().getConversations(); { const count = privateConversations.filter(e => e.hasUnreadMessages()).length; const count_container = this._html_tag.find(".container-indicator"); const count_tag = count_container.find(".chat-unread-counter"); count_container.toggle(count > 0); count_tag.text(count); } { const count_tag = this._html_tag.find(".chat-counter"); if(privateConversations.length == 0) count_tag.text(tr("No conversations")); else if(privateConversations.length == 1) count_tag.text(tr("One conversation")); else count_tag.text(privateConversations.length + " " + tr("conversations")); } } current_mode() : InfoFrameMode { return this._mode; } set_mode(mode: InfoFrameMode) { for(const mode in InfoFrameMode) this._html_tag.removeClass("mode-" + InfoFrameMode[mode]); this._html_tag.addClass("mode-" + mode); if(mode === InfoFrameMode.CLIENT_INFO && this._button_conversation) { //Will be called every time a client is shown const selected_client = this.handle.client_info().current_client(); const conversation = selected_client ? this.handle.private_conversations().findConversation(selected_client) : undefined; const visibility = (selected_client && selected_client.clientId() !== this.handle.handle.getClientId()) ? "visible" : "hidden"; if(this._button_conversation.style.visibility !== visibility) this._button_conversation.style.visibility = visibility; if(conversation) { this._button_conversation.innerText = tr("Open conversation"); } else { this._button_conversation.innerText = tr("Start a conversation"); } } else if(mode === InfoFrameMode.MUSIC_BOT) { //TODO? } } } export enum FrameContent { NONE, PRIVATE_CHAT, CHANNEL_CHAT, CLIENT_INFO, MUSIC_BOT } export class Frame { readonly handle: ConnectionHandler; private infoFrame: InfoFrame; private htmlTag: JQuery; private containerInfo: JQuery; private containerChannelChat: JQuery; private _content_type: FrameContent; private clientInfo: ClientInfo; private musicInfo: MusicInfo; private channelConversations: ConversationManager; private privateConversations: PrivateConversationManager; constructor(handle: ConnectionHandler) { this.handle = handle; this._content_type = FrameContent.NONE; this.infoFrame = new InfoFrame(this); this.privateConversations = new PrivateConversationManager(handle); this.channelConversations = new ConversationManager(handle); this.clientInfo = new ClientInfo(this); this.musicInfo = new MusicInfo(this); this._build_html_tag(); this.show_channel_conversations(); this.info_frame().update_chat_counter(); } html_tag() : JQuery { return this.htmlTag; } info_frame() : InfoFrame { return this.infoFrame; } content_type() : FrameContent { return this._content_type; } destroy() { this.htmlTag && this.htmlTag.remove(); this.htmlTag = undefined; this.infoFrame && this.infoFrame.destroy(); this.infoFrame = undefined; this.clientInfo && this.clientInfo.destroy(); this.clientInfo = undefined; this.musicInfo && this.musicInfo.destroy(); this.musicInfo = undefined; this.privateConversations && this.privateConversations.destroy(); this.privateConversations = undefined; this.channelConversations && this.channelConversations.destroy(); this.channelConversations = undefined; this.containerInfo && this.containerInfo.remove(); this.containerInfo = undefined; this.containerChannelChat && this.containerChannelChat.remove(); this.containerChannelChat = undefined; } private _build_html_tag() { this.htmlTag = $("#tmpl_frame_chat").renderTag(); this.containerInfo = this.htmlTag.find(".container-info"); this.containerChannelChat = this.htmlTag.find(".container-chat"); this.infoFrame.html_tag().appendTo(this.containerInfo); } private_conversations() : PrivateConversationManager { return this.privateConversations; } channel_conversations() : ConversationManager { return this.channelConversations; } client_info() : ClientInfo { return this.clientInfo; } music_info() : MusicInfo { return this.musicInfo; } private _clear() { this._content_type = FrameContent.NONE; this.containerChannelChat.children().detach(); } show_private_conversations() { if(this._content_type === FrameContent.PRIVATE_CHAT) return; this._clear(); this._content_type = FrameContent.PRIVATE_CHAT; this.containerChannelChat.append(this.privateConversations.htmlTag); this.privateConversations.handlePanelShow(); this.infoFrame.set_mode(InfoFrameMode.PRIVATE_CHAT); } show_channel_conversations() { if(this._content_type === FrameContent.CHANNEL_CHAT) return; this._clear(); this._content_type = FrameContent.CHANNEL_CHAT; this.containerChannelChat.append(this.channelConversations.htmlTag); this.channelConversations.handlePanelShow(); this.infoFrame.set_mode(InfoFrameMode.CHANNEL_CHAT); } show_client_info(client: ClientEntry) { this.clientInfo.set_current_client(client); this.infoFrame.set_mode(InfoFrameMode.CLIENT_INFO); /* specially needs an update here to update the conversation button */ if(this._content_type === FrameContent.CLIENT_INFO) return; this.clientInfo.previous_frame_content = this._content_type; this._clear(); this._content_type = FrameContent.CLIENT_INFO; this.containerChannelChat.append(this.clientInfo.html_tag()); } show_music_player(client: MusicClientEntry) { this.musicInfo.set_current_bot(client); if(this._content_type === FrameContent.MUSIC_BOT) return; this.infoFrame.set_mode(InfoFrameMode.MUSIC_BOT); this.musicInfo.previous_frame_content = this._content_type; this._clear(); this._content_type = FrameContent.MUSIC_BOT; this.containerChannelChat.append(this.musicInfo.html_tag()); } set_content(type: FrameContent) { if(this._content_type === type) return; if(type === FrameContent.CHANNEL_CHAT) this.show_channel_conversations(); else if(type === FrameContent.PRIVATE_CHAT) this.show_private_conversations(); else { this._clear(); this._content_type = FrameContent.NONE; this.infoFrame.set_mode(InfoFrameMode.NONE); } } }