Overte-community-apps-Alezi.../applications/armored-chat/armored_chat.js
Armored Dragon c4a05f976f
Cleanup
Changed branding from Armored Dragon to Overte.
Added to metadata.js.

Signed-off-by: Armored Dragon <publicmail@armoreddragon.com>
2024-02-22 16:56:14 -06:00

234 lines
7.5 KiB
JavaScript

//
// armored_chat.js
//
// Created by Armored Dragon, 2024.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
(function () {
"use strict";
// TODO: Encryption + PMs
// TODO: Find window init event method
var app_is_visible = false;
var settings = {
max_history: 250,
compact_chat: false,
external_window: false,
};
var app_data = { current_page: "domain" };
// Global vars
var ac_tablet;
var chat_overlay_window;
var app_button;
const channels = ["domain", "local", "system"];
var max_local_distance = 20; // Maximum range for the local chat
startup();
function startup() {
ac_tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
app_button = ac_tablet.addButton({
icon: Script.resolvePath("./img/icon.png"),
text: "CHAT",
isActive: app_is_visible,
});
// When script ends, remove itself from tablet
Script.scriptEnding.connect(function () {
console.log("Shutting Down");
ac_tablet.removeButton(app_button);
chat_overlay_window.close();
});
// Overlay button toggle
app_button.clicked.connect(toggleMainChatWindow);
_openWindow();
}
function toggleMainChatWindow() {
app_is_visible = !app_is_visible;
console.log(`App is now ${app_is_visible ? "visible" : "hidden"}`);
app_button.editProperties({ isActive: app_is_visible });
chat_overlay_window.visible = app_is_visible;
// External window was closed; the window does not exist anymore
if (chat_overlay_window.title == "" && app_is_visible) {
_openWindow();
}
}
function _openWindow() {
chat_overlay_window = new Desktop.createWindow(Script.resourcesPath() + "qml/hifi/tablet/DynamicWebview.qml", {
title: "Overte Chat",
size: { x: 550, y: 400 },
additionalFlags: Desktop.ALWAYS_ON_TOP,
visible: app_is_visible, // FIXME Invalid?
presentationMode: Desktop.PresentationMode.VIRTUAL,
});
chat_overlay_window.visible = app_is_visible; // The "visible" field in the Desktop.createWindow does not seem to work. Force set it to false
chat_overlay_window.closed.connect(toggleMainChatWindow);
chat_overlay_window.sendToQml({ url: Script.resolvePath("./index.html") });
// FIXME: Loadsettings need to happen after the window is initialized?
// Script.setTimeout(_loadSettings, 1000);
chat_overlay_window.webEventReceived.connect(onWebEventReceived);
}
// Initialize default message subscriptions
Messages.subscribe("chat");
// Messages.subscribe("system");
Messages.messageReceived.connect(receivedMessage);
function receivedMessage(channel, message) {
console.log(`Received message:\n${message}`);
var message = JSON.parse(message);
channel = channel.toLowerCase();
if (channel !== "chat") return;
message.channel = message.channel.toLowerCase();
// For now, while we are working on superseding Floof, we will allow compatibility with it.
// If for_app exists, it came from us and we are just sending the message so Floof can read it.
// We don't need to listen to this message.
if (message.for_app) return;
// Check the channel is valid
if (!channels.includes(message.channel)) return;
// FIXME: Not doing distance check?
// If message is local, and if player is too far away from location, don't do anything
if (channel === "local" && Vec3.distance(MyAvatar.position, message.position) < max_local_distance) return;
// Floof chat compatibility.
if (message.type) delete message.type;
// Update web view of to new message
_emitEvent({ type: "show_message", ...message });
// Display on popup chat area
_overlayMessage({ sender: message.displayName, message: message });
}
function onWebEventReceived(event) {
console.log(`New web event:\n${event}`);
// FIXME: Lazy!
// Checks to see if the event is a JSON object
if (!event.includes("{")) return;
var parsed = JSON.parse(event);
// Not our app? Not our problem!
// if (parsed.app !== "ArmoredChat") return;
switch (parsed.type) {
case "page_update":
app_data.current_page = parsed.page;
break;
case "send_message":
_sendMessage(parsed.message);
break;
case "open_url":
Window.openUrl(parsed.message.toString());
break;
case "setting_update":
// Update local settings
settings[parsed.setting_name] = parsed.setting_value;
// Save local settings
_saveSettings();
switch (parsed.setting_name) {
case "external_window":
console.log(parsed.setting_value);
chat_overlay_window.presentationMode = parsed.setting_value ? Desktop.PresentationMode.NATIVE : Desktop.PresentationMode.VIRTUAL;
break;
}
break;
case "initialized":
_loadSettings();
break;
}
}
//
// Sending messages
// These functions just shout out their messages. We are listening to messages in an other function, and will record all heard messages there
function _sendMessage(message) {
Messages.sendMessage(
"chat",
JSON.stringify({
position: MyAvatar.position,
message: message,
displayName: MyAvatar.sessionDisplayName,
channel: app_data.current_page,
action: "send_chat_message",
})
);
// FloofyChat Compatibility
Messages.sendMessage(
"Chat",
JSON.stringify({
position: MyAvatar.position,
message: message,
displayName: MyAvatar.sessionDisplayName,
channel: app_data.current_page.charAt(0).toUpperCase() + app_data.current_page.slice(1),
type: "TransmitChatMessage",
for_app: "Floof",
})
);
// Show overlay of the message you sent
_overlayMessage({ sender: MyAvatar.sessionDisplayName, message: message });
}
function _overlayMessage(message) {
// Floofchat compatibility
// This makes it so that our own messages are not rendered.
// For now, Floofchat has priority over notifications as they use a strange system I don't want to touch yet.
if (!message.action) return;
Messages.sendLocalMessage(
"Floof-Notif",
JSON.stringify({
sender: message.sender,
text: message.message,
color: { red: 122, green: 122, blue: 122 },
})
);
}
function _loadSettings() {
console.log("Loading config");
settings = Settings.getValue("ArmoredChat-Config", settings);
console.log("\nSettings follow:");
console.log(JSON.stringify(settings, " ", 4));
// Compact chat
if (settings.compact_chat) {
_emitEvent({ type: "setting_update", setting_name: "compact_chat", setting_value: true });
}
// External Window
if (settings.external_window) {
chat_overlay_window.presentationMode = settings.external_window ? Desktop.PresentationMode.NATIVE : Desktop.PresentationMode.VIRTUAL;
_emitEvent({ type: "setting_update", setting_name: "external_window", setting_value: true });
}
}
function _saveSettings() {
console.log("Saving config");
Settings.setValue("ArmoredChat-Config", settings);
}
/**
* Emit a packet to the HTML front end. Easy communication!
* @param {Object} packet - The Object packet to emit to the HTML
* @param {("setting_update"|"show_message")} packet.type - The type of packet it is
*/
function _emitEvent(packet = { type: "" }) {
chat_overlay_window.emitScriptEvent(JSON.stringify(packet));
}
})();