diff --git a/gui/main.js b/gui/main.js index 28fe54fc..4c13ca96 100644 --- a/gui/main.js +++ b/gui/main.js @@ -100,7 +100,8 @@ const configDefaultSettings = "max_retry_attempts" : 5, \ "enable_auto_retry" : "False", \ "tx_delay" : 0, \ - "auto_start": 0 \ + "auto_start": 0, \ + "notification": 1 \ }'; if (!fs.existsSync(configPath)) { @@ -410,6 +411,11 @@ ipcMain.on("request-show-chat-window", () => { chat.show(); }); +ipcMain.on("request-clear-chat-connected", () => { + //Clear chat window's connected with text + chat.webContents.send("action-clear-reception-status"); +}); + // UPDATE TNC CONNECTION ipcMain.on("request-update-tnc-ip", (event, data) => { win.webContents.send("action-update-tnc-ip", data); @@ -479,6 +485,20 @@ ipcMain.on("request-update-transmission-status", (event, arg) => { ipcMain.on("request-update-reception-status", (event, arg) => { win.webContents.send("action-update-reception-status", arg); + chat.webContents.send("action-update-reception-status", arg); + +}); + +//Called by main to query chat if there are new messages +ipcMain.on("request-update-unread-messages",() => { + //mainLog.info("Got request to check if chat has new messages") + chat.webContents.send("action-update-unread-messages"); + +}); +//Called by chat to notify main if there are new messages +ipcMain.on("request-update-unread-messages-main", (event,arg) => { + win.webContents.send("action-update-unread-messages-main",arg); + //mainLog.info("Received reply from chat and ?new messages = " +arg); }); ipcMain.on("request-open-tnc-log", () => { diff --git a/gui/preload-chat.js b/gui/preload-chat.js index 4c600cf7..121f4faa 100644 --- a/gui/preload-chat.js +++ b/gui/preload-chat.js @@ -661,8 +661,25 @@ ipcRenderer.on("return-select-user-image", (event, arg) => { }); }); +ipcRenderer.on("action-update-reception-status", (event, arg) => { + var data = arg["data"][0]; + + document.getElementById("txtConnectedWithChat").textContent = data.dxcallsign; +}); +ipcRenderer.on("action-clear-reception-status", (event) => { + //Clear connected with textbox + let cwc = document.getElementById("txtConnectedWithChat"); + if (cwc.textContent != "------") { + cwc.textContent = "------"; + //console.log("Reseting connected with"); + } +}); + ipcRenderer.on("action-update-transmission-status", (event, arg) => { var data = arg["data"][0]; + + document.getElementById("txtConnectedWithChat").textContent = data.dxcallsign; + console.log(data.status); if (data.uuid !== "no-uuid") { db.get(data.uuid, { @@ -768,6 +785,7 @@ ipcRenderer.on("action-new-msg-received", (event, arg) => { obj.filename = "null"; obj.filetype = "null"; obj.file = "null"; + obj.new = 1; console.log(obj); add_obj_to_database(obj); update_chat_obj_by_uuid(obj.uuid); @@ -796,6 +814,7 @@ ipcRenderer.on("action-new-msg-received", (event, arg) => { obj.filename = "null"; obj.filetype = "null"; obj.file = "null"; + obj.new = 1; add_obj_to_database(obj); update_chat_obj_by_uuid(obj.uuid); @@ -815,7 +834,7 @@ ipcRenderer.on("action-new-msg-received", (event, arg) => { obj.filename = "null"; obj.filetype = "null"; obj.file = "null"; - + obj.new = 1; add_obj_to_database(obj); update_chat_obj_by_uuid(obj.uuid); @@ -834,7 +853,7 @@ ipcRenderer.on("action-new-msg-received", (event, arg) => { obj.filename = "null"; obj.filetype = "null"; obj.file = "null"; - + obj.new = 1; add_obj_to_database(obj); update_chat_obj_by_uuid(obj.uuid); @@ -862,6 +881,7 @@ ipcRenderer.on("action-new-msg-received", (event, arg) => { obj.filetype = splitted_data[7]; //obj.file = btoa(splitted_data[8]); obj.file = FD.btoa_FD(splitted_data[8]); + obj.new=1; } else if (splitted_data[1] == "req" && splitted_data[2] == "0") { obj.uuid = uuidv4().toString(); obj.timestamp = Math.floor(Date.now() / 1000); @@ -874,7 +894,7 @@ ipcRenderer.on("action-new-msg-received", (event, arg) => { obj.filename = "null"; obj.filetype = "null"; obj.file = "null"; - + obj.new=1; if (config.enable_request_profile == "True") { sendUserData(item.dxcallsign); } @@ -890,7 +910,7 @@ ipcRenderer.on("action-new-msg-received", (event, arg) => { obj.filename = "null"; obj.filetype = "null"; obj.file = "null"; - + obj.new=1; if (config.enable_request_shared_folder == "True") { sendSharedFolderList(item.dxcallsign); } @@ -911,7 +931,7 @@ ipcRenderer.on("action-new-msg-received", (event, arg) => { obj.filename = "null"; obj.filetype = "null"; obj.file = "null"; - + obj.new=1; if (config.enable_request_shared_folder == "True") { sendSharedFolderFile(item.dxcallsign, name); } @@ -927,7 +947,7 @@ ipcRenderer.on("action-new-msg-received", (event, arg) => { obj.filename = "null"; obj.filetype = "null"; obj.file = "null"; - + obj.new=1; console.log(splitted_data); let userData = new Object(); userData.user_info_image = splitted_data[2]; @@ -956,7 +976,7 @@ ipcRenderer.on("action-new-msg-received", (event, arg) => { obj.filename = "null"; obj.filetype = "null"; obj.file = "null"; - + obj.new=1; console.log(splitted_data); let userData = new Object(); @@ -984,6 +1004,7 @@ ipcRenderer.on("action-new-msg-received", (event, arg) => { obj.filename = sharedFileInfo[0]; obj.filetype = "application/octet-stream"; obj.file = FD.btoa_FD(sharedFileInfo[1]); + obj.new=1; } else { console.log("no rule matched for handling received data!"); } @@ -1023,7 +1044,7 @@ update_chat = function (obj) { } // add percent and bytes per minute if not existing -console.log(obj.percent) +//console.log(obj.percent) if (typeof obj.percent == "undefined") { obj.percent = 0; obj.bytesperminute = 0; @@ -1043,13 +1064,16 @@ var TimeDifference = (new Date().getTime()/1000) - obj.timestamp } } - + if (typeof obj.new == "undefined"){ + obj.new=0; + } + if (typeof config.max_retry_attempts == "undefined") { var max_retry_attempts = 3; } else { var max_retry_attempts = parseInt(config.max_retry_attempts); } - console.log(obj.msg); + //console.log(obj.msg); // define shortmessage if (obj.msg == "null" || obj.msg == "NULL") { var shortmsg = obj.type; @@ -1184,7 +1208,7 @@ var TimeDifference = (new Date().getTime()/1000) - obj.timestamp - ${dxcallsign} + ${dxcallsign} ${dxgrid} ${timestampHours} ${shortmsg} @@ -1214,6 +1238,11 @@ var TimeDifference = (new Date().getTime()/1000) - obj.timestamp .addEventListener("click", function () { //document.getElementById('chatModuleDxCall').value = dxcallsign; selected_callsign = dxcallsign; + //Reset unread messages and new message indicator + let clear = selected_callsign; + clearUnreadMessages(clear); + document.getElementById(`chat-${selected_callsign}-list-displaydxcall`).textContent=selected_callsign; + setTimeout(scrollMessagesToBottom, 200); //get user information @@ -1234,6 +1263,7 @@ var TimeDifference = (new Date().getTime()/1000) - obj.timestamp // short message document.getElementById("chat-" + dxcallsign + "-list-shortmsg").innerHTML = shortmsg; + if (obj.new==1) document.getElementById(`chat-${obj.dxcallsign}-list-displaydxcall`).textContent="*" +obj.dxcallsign; } // APPEND MESSAGES TO CALLSIGN @@ -1243,7 +1273,10 @@ var TimeDifference = (new Date().getTime()/1000) - obj.timestamp if (config.enable_auto_retry.toUpperCase() == "TRUE") { checkForWaitingMessages(obj.dxcallsign); } - + if (obj.new == 1) + { + showOsPopUp("Ping from " + obj.dxcallsign,"You've been ping'd!"); + } var new_message = `

snr: ${obj.snr} - ${timestamp}

@@ -1294,6 +1327,11 @@ var TimeDifference = (new Date().getTime()/1000) - obj.timestamp var message_html = obj.msg.replaceAll(/\n/g, "
"); if (obj.type == "received") { + if (obj.new == 1) + { + showOsPopUp("Message received from " + obj.dxcallsign,obj.msg); + } + var new_message = `
@@ -1384,7 +1422,7 @@ var TimeDifference = (new Date().getTime()/1000) - obj.timestamp } if (obj.type == "transmit") { - console.log(obj); + //console.log(obj); //console.log('msg-' + obj._id + '-status') if (obj.status == "failed") { @@ -1457,11 +1495,11 @@ var TimeDifference = (new Date().getTime()/1000) - obj.timestamp /* UPDATE EXISTING ELEMENTS */ } else if (document.getElementById("msg-" + obj._id)) { - console.log("element already exists......"); - console.log(obj); + //console.log("element already exists......"); + //console.log(obj); - console.log(obj.status) - console.log(obj.attempt) + // console.log(obj.status) + // console.log(obj.attempt) @@ -1844,6 +1882,7 @@ add_obj_to_database = function (obj) { status: obj.status, snr: obj.snr, attempt: obj.attempt, + new: obj.new, _attachments: { [obj.filename]: { content_type: obj.filetype, @@ -2093,6 +2132,7 @@ function createChatIndex() { "attempt", "bytesperminute", "_attachments", + "new", ], }, }) @@ -2232,9 +2272,9 @@ function getSetUserSharedFolder(selected_callsign) { .then(function (data) { console.log(data); - console.log(data.user_shared_folder); if (typeof data.user_shared_folder !== "undefined") { + console.log(data.user_shared_folder); // shared folder table var icons = [ "aac", @@ -2620,6 +2660,12 @@ ipcRenderer.on("update-config", (event, data) => { config = data; }); +ipcRenderer.on("action-update-unread-messages", (event) => { + checkForNewMessages().then(function(count) { + ipcRenderer.send("request-update-unread-messages-main",count); + }); +}); + // https://stackoverflow.com/a/18650828 function formatBytes(bytes, decimals = 2) { if (!+bytes) return "0 Bytes"; @@ -2749,3 +2795,56 @@ function checkForWaitingMessages(dxcall) { console.log(err); }); } + +async function checkForNewMessages() +{ + var newmsgs; + await db.find({ + selector: { + new: {$eq: 1}, + }, limit:1, + }) + .then(function (result) { + if (result.docs.length >0) + newmsgs=true; + else + newmsgs=false; + }) + .catch(function (err) { + console.log(err); + }); + return newmsgs; +} + +function clearUnreadMessages(dxcall) { + //console.log(dxcall); + db.find({ + selector: { + dxcallsign: dxcall, + new: {$eq: 1}, + } + }) + .then(function (result) { + //console.log(result); + //console.log ("New messages count to clear for " + dxcall + ": " + result.docs.length) + result.docs.forEach(function (item) { + db.upsert(item._id, function (doc) { + doc.new=0; + //console.log("Clearing new on _id " + item._id); + return doc; + }); + }); + }) + .catch(function (err) { + console.log(err); + }); +} + +//Have the operating system show a notification popup +function showOsPopUp(title, message) +{ + if (config.notification == 0) return; + const NOTIFICATION_TITLE = title; + const NOTIFICATION_BODY = message; + new Notification(NOTIFICATION_TITLE, { body: NOTIFICATION_BODY }); +} \ No newline at end of file diff --git a/gui/preload-main.js b/gui/preload-main.js index 61d0f45f..5fe94d3a 100644 --- a/gui/preload-main.js +++ b/gui/preload-main.js @@ -390,6 +390,12 @@ window.addEventListener("DOMContentLoaded", () => { document.getElementById("AutoStartSwitch").checked = false; } + if (config.notification == 1) { + document.getElementById("NotificationSwitch").checked = true; + } else { + document.getElementById("NotificationSwitch").checked = false; + } + // theme selector changeGuiDesign(config.theme); @@ -1213,6 +1219,17 @@ window.addEventListener("DOMContentLoaded", () => { FD.saveConfig(config, configPath); }); + //Handle change of Notification settings + document.getElementById("NotificationSwitch").addEventListener("click", () => { + if (document.getElementById("NotificationSwitch").checked == true) { + config.notification = 1; + } else { + config.notification = 0; + } + //fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); + FD.saveConfig(config, configPath); + }); + // enable fsk Switch clicked document.getElementById("fskModeSwitch").addEventListener("click", () => { if (document.getElementById("fskModeSwitch").checked == true) { @@ -1371,7 +1388,7 @@ window.addEventListener("DOMContentLoaded", () => { // Discord Link clicked document.getElementById("discordUrl").addEventListener("click", () => { - shell.openExternal("https://discord.gg/jnADeDtxUF"); + shell.openExternal("https://discord.freedata.app/"); }); // startTNC button clicked @@ -1938,7 +1955,16 @@ function signal_quality_perc_quad(rssi, perfect_rssi = 10, worst_rssi = -150) { } var lastHeard = ""; +var checkForNewMessageWait=85; + ipcRenderer.on("action-update-tnc-state", (event, arg) => { + //check for new messages + if (checkForNewMessageWait >= 100){ + //This is very expensive + ipcRenderer.send("request-update-unread-messages"); + checkForNewMessageWait=-1; + } + checkForNewMessageWait++; // update FFT if (typeof arg.fft !== "undefined") { // FIXME: WE need to fix this when disabled waterfall chart @@ -2258,6 +2284,7 @@ ipcRenderer.on("action-update-tnc-state", (event, arg) => { "bi bi-chat-fill text-success me-1"; } else { document.getElementById("spnConnectedWith").className = "bi bi-chat-fill"; + ipcRenderer.send("request-clear-chat-connected"); } // HAMLIB STATUS @@ -2894,6 +2921,22 @@ ipcRenderer.on("run-tnc-command-fec-iswriting", (event) => { sock.sendFecIsWriting(config.mycall); }); +//Change background color of RF Chat button if new messages are available +ipcRenderer.on("action-update-unread-messages-main", (event,data) => { + //Do something + if (data == true) + { + document.getElementById("openRFChat").classList.add("btn-warning") + document.getElementById("openRFChat").classList.remove("btn-secondary") + } + else + { + document.getElementById("openRFChat").classList.remove("btn-warning") + document.getElementById("openRFChat").classList.add("btn-secondary") + } +}); + + ipcRenderer.on("run-tnc-command", (event, arg) => { if (arg.command == "enable_mesh") { @@ -3090,7 +3133,7 @@ ipcRenderer.on("action-show-cq-toast-received", (event, data) => { let dxcallsign = data["data"][0]["dxcallsign"]; let dxgrid = data["data"][0]["dxgrid"]; let content = `cq from ${dxcallsign} (${dxgrid})`; - + showOsPopUp("CQ from " + dxcallsign,"Say hello!"); displayToast( (type = "success"), (icon = "bi-broadcast"), @@ -3777,4 +3820,13 @@ function autostart_tnc() { //Now start TNC document.getElementById("startTNC").click(); } +} + +//Have the operating system show a notification popup +function showOsPopUp(title, message) +{ + if (config.notification == 0) return; + const NOTIFICATION_TITLE = title; + const NOTIFICATION_BODY = message; + new Notification(NOTIFICATION_TITLE, { body: NOTIFICATION_BODY }); } \ No newline at end of file diff --git a/gui/src/chat-module.html b/gui/src/chat-module.html index dddc0c7d..3447b6e6 100644 --- a/gui/src/chat-module.html +++ b/gui/src/chat-module.html @@ -264,7 +264,18 @@ Help + + + + + ------
diff --git a/gui/src/index.html b/gui/src/index.html index fb187444..685683f0 100644 --- a/gui/src/index.html +++ b/gui/src/index.html @@ -189,7 +189,7 @@ data-bs-toggle="tooltip" data-bs-trigger="hover" data-bs-html="false" - title="Open the HF chat module. This is currently just a test and not finished, yet!" + title="Open the chat window.  The background will change to yellow if a new message is available." > RF Chat @@ -2911,6 +2911,23 @@ +
+ + +