TeaWeb/shared/js/ui/frames/chat_frame.ts
2020-07-18 00:18:02 +02:00

420 lines
No EOL
16 KiB
TypeScript

/* the bar on the right with the chats (Channel & Client) */
import {ClientEntry, MusicClientEntry} from "tc-shared/ui/client";
import {ConnectionHandler} from "tc-shared/ConnectionHandler";
import {ChannelEntry} from "tc-shared/ui/channel";
import {ServerEntry} from "tc-shared/ui/server";
import {openMusicManage} from "tc-shared/ui/modal/ModalMusicManage";
import {formatMessage} from "tc-shared/ui/frames/chat";
import {ClientInfo} from "tc-shared/ui/frames/side/client_info";
import {MusicInfo} from "tc-shared/ui/frames/side/music_info";
import {ConversationManager} from "tc-shared/ui/frames/side/ConversationManager";
import {PrivateConversationManager} from "tc-shared/ui/frames/side/PrivateConversationManager";
declare function setInterval(handler: TimerHandler, timeout?: number, ...arguments: any[]): number;
declare function setTimeout(handler: TimerHandler, timeout?: number, ...arguments: any[]): number;
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)
client.handle.fileManager.icons.generateTag(channel.properties.channel_icon_id).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)
this.handle.handle.fileManager.icons.generateTag(channel.properties.channel_icon_id).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)
this.handle.handle.fileManager.icons.generateTag(server.properties.virtualserver_icon_id).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 _info_frame: InfoFrame;
private _html_tag: JQuery;
private _container_info: JQuery;
private _container_chat: JQuery;
private _content_type: FrameContent;
private _client_info: ClientInfo;
private _music_info: MusicInfo;
private _channel_conversations: ConversationManager;
private _private_conversations: PrivateConversationManager;
constructor(handle: ConnectionHandler) {
this.handle = handle;
this._content_type = FrameContent.NONE;
this._info_frame = new InfoFrame(this);
this._private_conversations = new PrivateConversationManager(handle);
this._channel_conversations = new ConversationManager(handle);
this._client_info = new ClientInfo(this);
this._music_info = new MusicInfo(this);
this._build_html_tag();
this.show_channel_conversations();
this.info_frame().update_chat_counter();
}
html_tag() : JQuery { return this._html_tag; }
info_frame() : InfoFrame { return this._info_frame; }
content_type() : FrameContent { return this._content_type; }
destroy() {
this._html_tag && this._html_tag.remove();
this._html_tag = undefined;
this._info_frame && this._info_frame.destroy();
this._info_frame = undefined;
this._client_info && this._client_info.destroy();
this._client_info = undefined;
this._music_info && this._music_info.destroy();
this._music_info = undefined;
this._private_conversations && this._private_conversations.destroy();
this._private_conversations = undefined;
this._channel_conversations && this._channel_conversations.destroy();
this._channel_conversations = undefined;
this._container_info && this._container_info.remove();
this._container_info = undefined;
this._container_chat && this._container_chat.remove();
this._container_chat = undefined;
}
private _build_html_tag() {
this._html_tag = $("#tmpl_frame_chat").renderTag();
this._container_info = this._html_tag.find(".container-info");
this._container_chat = this._html_tag.find(".container-chat");
this._info_frame.html_tag().appendTo(this._container_info);
}
private_conversations() : PrivateConversationManager {
return this._private_conversations;
}
channel_conversations() : ConversationManager {
return this._channel_conversations;
}
client_info() : ClientInfo {
return this._client_info;
}
music_info() : MusicInfo {
return this._music_info;
}
private _clear() {
this._content_type = FrameContent.NONE;
this._container_chat.children().detach();
}
show_private_conversations() {
if(this._content_type === FrameContent.PRIVATE_CHAT)
return;
this._clear();
this._content_type = FrameContent.PRIVATE_CHAT;
this._container_chat.append(this._private_conversations.htmlTag);
this._private_conversations.handlePanelShow();
this._info_frame.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._container_chat.append(this._channel_conversations.htmlTag);
this._channel_conversations.handlePanelShow();
this._info_frame.set_mode(InfoFrameMode.CHANNEL_CHAT);
}
show_client_info(client: ClientEntry) {
this._client_info.set_current_client(client);
this._info_frame.set_mode(InfoFrameMode.CLIENT_INFO); /* specially needs an update here to update the conversation button */
if(this._content_type === FrameContent.CLIENT_INFO)
return;
this._client_info.previous_frame_content = this._content_type;
this._clear();
this._content_type = FrameContent.CLIENT_INFO;
this._container_chat.append(this._client_info.html_tag());
}
show_music_player(client: MusicClientEntry) {
this._music_info.set_current_bot(client);
if(this._content_type === FrameContent.MUSIC_BOT)
return;
this._info_frame.set_mode(InfoFrameMode.MUSIC_BOT);
this._music_info.previous_frame_content = this._content_type;
this._clear();
this._content_type = FrameContent.MUSIC_BOT;
this._container_chat.append(this._music_info.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._info_frame.set_mode(InfoFrameMode.NONE);
}
}
}