From cac70f8e3dbad9b8c462447b83a0998fb1553b16 Mon Sep 17 00:00:00 2001 From: Bryan Date: Mon, 5 Aug 2024 09:42:28 -0600 Subject: [PATCH] fix logic in goBack(), start adding functionality for call handling, add HeaderBox as exported function in messagebox module --- messagebox.lib.js | 28 +-- messagecenter.app.js | 401 ++++++++++++++++++++++++++++--------------- messagegui.lib.js | 34 ++-- 3 files changed, 279 insertions(+), 184 deletions(-) diff --git a/messagebox.lib.js b/messagebox.lib.js index f6ec588..aa4c267 100644 --- a/messagebox.lib.js +++ b/messagebox.lib.js @@ -27,7 +27,7 @@ const centerString = (str, x, y, w) => { g.drawString(str, x + (w / 2), y); }; -const HeaderBox = function(msg, messageRect) { +HeaderBox = function(msg, messageRect) { this.icon = require("messageicons").getImage(msg); this.color = require("messageicons").getColor(msg, {default:g.theme.fg2}); this.iconW = 48; @@ -226,32 +226,8 @@ MessageBox.prototype.scroll = function(dy) { this.draw(); }; -// MessageBox.prototype.drawFooter = function() { -// // left hint: swipe from left for main menu -// g.reset().clearRect(Bangle.appRect.x, Bangle.appRect.y2-options.fh, Bangle.appRect.x2, Bangle.appRect.y2) -// .setFont(fontTiny) -// .setFontAlign(-1, 1) // bottom left -// .drawString( -// "\0"+atob("CAiBAEgkEgkSJEgA"), // >> -// Bangle.appRect.x + 1, Bangle.appRect.y2 -// ); -// // center message count+hints: swipe up/down for next/prev message -// const footer = ` ${messageNum+1}/${MESSAGES.length} `; -// const fw = g.stringWidth(footer); -// g.setFontAlign(0, 1); // bottom center -// g.drawString(footer, Bangle.appRect.x+Bangle.appRect.w/2, Bangle.appRect.y2); -// if (messageNum < MESSAGES.length - 1 && this.bottom) -// g.drawString("\0"+atob("CAiBAABBIhRJIhQI"), Bangle.appRect.x+Bangle.appRect.w/2-fw/2, Bangle.appRect.y2); // v swipe to next -// if (messageNum > 0 && this.top) -// g.drawString("\0"+atob("CAiBABAoRJIoRIIA"), Bangle.appRect.x+Bangle.appRect.w/2+fw/2, Bangle.appRect.y2); // ^ swipe to prev -// // right hint: swipe from right for message actions -// g.setFontAlign(1, 1) // bottom right -// .drawString( -// "\0"+atob("CAiBABIkSJBIJBIA"), // << -// Bangle.appRect.x2 - 1, Bangle.appRect.y2 -// ); -// }; +module.exports.HeaderBox = HeaderBox; module.exports.MessageBox = MessageBox; module.exports.setOptions = this.setOptions; module.exports.setClipRect = this.setClipRect; diff --git a/messagecenter.app.js b/messagecenter.app.js index 92923dc..42b063a 100644 --- a/messagecenter.app.js +++ b/messagecenter.app.js @@ -1,94 +1,5 @@ -// Bangle.MESSAGES = [ -// {"t":"add","id":1720281666,"src":"SMS Message","title":"Hayley Thiessen, Wifey","subject":"", -// "body":"5 * short message *5", -// "sender":"","positive":true,"negative":true,"new":true,"handled":true, "show": true}, -// -// {"t":"add","id":1720281662,"src":"SMS Message","title":"Hayley Thiessen, Wifey","subject":"", -// "body":"1 ***** This is a long message from my wife. I want to make it take up more than a screenful. That way we can test out scrolling. ****1", -// "sender":"","positive":true,"negative":true,"new":false,"handled":true, "show": true}, -// -// {"t":"add","id":1720281663,"src":"SMS Message","title":"Hayley Thiessen, Wifey","subject":"", -// "body":"2 ***** This is a long message from my wife. I want to make it take up more than a screenful. That way we can test out scrolling. ****2", -// "sender":"","positive":true,"negative":true,"new":false,"handled":true, "show": true}, -// -// {"t":"add","id":1720281667,"src":"SMS Message","title":"Hayley Thiessen","subject":"", -// "body":"6 * short message *6", -// "sender":"","positive":true,"negative":true,"new":false,"handled":true, "show": true}, -// -// {"t":"add","id":1720281664,"src":"SMS Message","title":"Hayley Thiessen, Wifey","subject":"", -// "body":"3 ***** This is a long message from my wife. I want to make it take up more than a screenful. That way we can test out scrolling. ****3", -// "sender":"","positive":true,"negative":true,"new":true,"handled":true, "show": true}, -// -// {"t":"add","id":1720281665,"src":"SMS Message","title":"Hayley Thiessen, Wifey","subject":"", -// "body":"4 ***** This is a long message from my wife. I want to make it take up more than a screenful. That way we can test out scrolling. ****4", -// "sender":"","positive":true,"negative":true,"new":false,"handled":true, "show": true}, -// -// ]; +//{ - -let idle = false; -let haveNewMessage = false; -let previousActive; -let active; -let buzzing; -let events = {}; -let timeouts = {}; -let cleanup = function() {}; // we don't want cleanup function to do anything until we actually need it - -const goBack = function(timedOut) { - console.log("previousActive = ", previousActive); - switch (previousActive) { - case "alarm": return showAlarm(); - case "call": return showCall(); - case "message": return showMessage(); - case "map": return showMap(); - case "music": return showMusic(); - default: - if (!timedOut) Bangle.MESSAGES.forEach((m) => {if (!m.new) m.show = false;}); - console.log("write messages"); - console.log("Bangle.MESSAGES", Bangle.MESSAGES); - require("messages").write(Bangle.MESSAGES); - cleanup = _cleanup; - Bangle.showClock(); - } -}; - -const setListener = function(event, callback) { - if (!event || !callback) return; - // console.log("setListener"); - events[event] = callback; - Bangle.on(event, callback); -}; - -const _cleanup = function() { - for (let e in events) if (e) Bangle.removeListener(e, events[e]); - for (let t in timeouts) if (timeouts[t]) clearTimeout(timeouts[t]); -}; - -const clearTimeouts = function() { - for (let t in timeouts) if (timeouts[t]) clearTimeout(timeouts[t]); -}; - -// placeholder functions -const showNoMessages = function() { - -}; - -const showMusic = function() { - -}; - -const showMap = function() { - -}; - -const showAlarm = function() { - -}; - -const showCall = function() { - -}; //let settings = require('Storage').readJSON("messages.settings.json", true) || {}; //const settings = () => require("messagegui").settings(); const fontTiny = "6x8"; // fixed size, don't use this for important things @@ -105,54 +16,116 @@ const showCall = function() { // }; // setFont(); -Bangle.loadWidgets(); -require("widget_utils").hide(); +let idle = false; +let haveNewMessage = false; +let active; +let buzzing; +let events = {}; +let timeouts = {}; +let cleanup = function() {}; // we don't want cleanup function to do anything until we actually need it +let previous = []; +let msgIdx; +let call; +let alarm; +let map; +let music; -events.saveMessages = function() { - require("messages").write(Bangle.MESSAGES); +const setActive = function(newActive) { + if (!newActive) return; + if (active && !previous.includes(active) && newActive !== active) previous.push(active); + active = newActive; + console.log(previous); +} + +const setListener = function(event, callback) { + if (!event || !callback) return; + events[event] = callback; + Bangle.on(event, events[event]); }; -E.on("kill", events.saveMessages); - -const newMessage = (type, msg) => { - console.log("new message"); - console.log(type, msg); - if (type === "text" && active === "message") { - if (idle) showText(Bangle.MESSAGES); // we are idle so show new messages right away - else haveNewMessage = true; // otherwise set new message flag and wait until idle - } - // TODO deal with other types of messages -}; -setListener("breakingnews", newMessage); - -// Check for new messages, wait until there is no interaction for `idleTime` ms -const checkForNewMessages = function(idleTime) { - idleTime = idleTime ?? 3000; // how much time without interaction before we are considered idle - idle = false; - if (timeouts.idleTimer) clearTimeout(timeouts.idleTimer); - timeouts.idleTimer = setTimeout(() => { - if (haveNewMessage) { - haveNewMessage = false; - showText(Bangle.MESSAGES); - } - idle = true; - }, idleTime); +const _cleanup = function() { + for (let e in events) if (e) Bangle.removeListener(e, events[e]); + for (let t in timeouts) if (timeouts[t]) clearTimeout(timeouts[t]); + require("messages").stopBuzz(); }; -const setBusy = function() { - idle = false; - if (timeouts.idleTimer) clearTimeout(timeouts.idleTimer); - timeouts.idleTimer = undefined; +const clearTimeouts = function() { + for (let t in timeouts) if (timeouts[t]) clearTimeout(timeouts[t]); }; -/** - * @param showAll {bool} true to show all messages, false to only show new messages, default: false - */ -const showText = function(showAll) { - Bangle.setUI(); // make sure to clear setUI from anything previous - if (active != "message") previousActive = active; - active = "message"; +const showNoMessages = function() { + + g.reset().clear(); + g.setFont("12x20").setFontAlign(0,0); + g.drawString("No Messages!", Bangle.appRect.x + (Bangle.appRect.w / 2), Bangle.appRect.y + (Bangle.appRect.h / 2)); + + Bangle.setUI({ + mode: "custom", + btn: goBack(), + remove: cleanup + }); +}; + +const showMusic = function(music) { + active = "music"; + + Bangle.setUI({ + mode: "custom", + btn: goBack(), + remove: cleanup + }); +}; + +const showMap = function(map) { + active = "map"; + + Bangle.setUI({ + mode: "custom", + btn: goBack(), + remove: cleanup + }); +}; + +const showAlarm = function(alarm) { + active = "alarm"; + + Bangle.setUI({ + mode: "custom", + btn: goBack(), + remove: cleanup + }); +}; + +const showCall = function(call) { + Bangle.setUI(); // clear from previous + const HeaderBox = new require("messagebox").HeaderBox; + let header = new HeaderBox(call, Bangle.appRect); + g.reset().clear().setFont("12x20") + header.draw(Bangle.appRect); + let str = g.wrapString(JSON.stringify(call),g.getWidth()).join("\n"); + g.drawString(str, 0, 60); + console.log("call: ", call); + + const handler = function(e) { + console.log(e); + }; + + Bangle.setUI({ + mode: "custom", + drag: handler, + btn: goBack, + remove: cleanup + }); +}; + +const showText = function(messageNum) { + g.reset().clear(); + if (!Bangle.MESSAGES.length) return goBack(); // no messages setBusy(); // busy until everything is set up + let showAll = false; + if (messageNum === undefined) {messageNum = 0; showAll = true;} + else if (messageNum >= Bangle.MESSAGES.length - 1) messageNum = Bangle.MESSAGES.length - 1; + Bangle.setUI(); // make sure to clear setUI from anything previous let switching = false; let MessageBox = require("messagebox").MessageBox; require("messagebox").setOptions({fh: 20}); @@ -160,15 +133,13 @@ const showText = function(showAll) { const delay = 30; const swipeThreshold = 20; let mode = "scroll"; // one of "scroll", "next", "prev" (switch to next/prev message), "swipe" (swipe to delete or archive) - let messageNum = 0; + msgIdx = messageNum; // global message index // TODO we might have to append array of (m.show && !m.new) to array of m.new so that all new messages are at the beginning of list let messageList = showAll ? Bangle.MESSAGES : Bangle.MESSAGES.filter(m => m.new || m.show); - if (!messageList.length) { - // console.log("No messages") - return; - } -// Bangle.setLocked(false); // TODO make as option -// Bangle.setLCDPower(true); // TODO make as option + if (!messageList.length) return goBack(); + + // Bangle.setLocked(false); // TODO make as option + // Bangle.setLCDPower(true); // TODO make as option let msgBoxes = []; let i = 0; @@ -230,7 +201,10 @@ const showText = function(showAll) { Bangle.setUI(); return goBack(); // no more messages } - if (messageNum === msgBoxes.length) messageNum--; // we removed the last message, go to previous message + if (messageNum === msgBoxes.length) { + messageNum--; // we removed the last message, go to previous message + msgIdx = messageNum; // update global message index + } // otherwise messageNum is automatically the index of the next message now refresh(); msgBoxes[messageNum].draw(); @@ -275,6 +249,7 @@ const showText = function(showAll) { if (!removeCurrent) { if (messageNum < msgBoxes.length) { messageNum++; + msgIdx = messageNum; // update global message index refresh(); } } @@ -309,6 +284,7 @@ const showText = function(showAll) { if (!removeCurrent) { if (messageNum > 0) { messageNum--; + msgIdx = messageNum; // update global message index refresh(); } } @@ -350,7 +326,7 @@ const showText = function(showAll) { const msgBox = msgBoxes[messageNum]; return new Promise((resolve, _reject) => { let animate = () => { - msgBox.xOffset -= step + msgBox.xOffset -= step; drawLeftBackground(); if (msgBox.xOffset <= endX) { return resolve(); @@ -516,17 +492,156 @@ const showText = function(showAll) { msgBoxes[messageNum].draw(); drawFooter(); checkForNewMessages(); +}; // function showText + +// Check for new messages, wait until there is no interaction for `idleTime` ms +const checkForNewMessages = function(idleTime) { + idleTime = idleTime ?? 3000; // how much time without interaction before we are considered idle + idle = false; + if (timeouts.idleTimer) clearTimeout(timeouts.idleTimer); + timeouts.idleTimer = setTimeout(() => { + if (haveNewMessage) { + haveNewMessage = false; + let idx = Bangle.MESSAGES.findIndex(m => !m.handled); + if (idx >= 0) { + for (let m of Bangle.MESSAGES) m.handled = true; // set all text messages as handled + setActive("text"); + return showText(idx); + } else { + setActive("text"); + return showText(msgIdx); + } + } + idle = true; + }, idleTime); }; +const setBusy = function() { + idle = false; + if (timeouts.idleTimer) clearTimeout(timeouts.idleTimer); + timeouts.idleTimer = undefined; +}; + +const goBack = function(timedOut) { // TODO do we want this as a stack or by priority? + idle = true; + if (buzzing) require("messages").stopBuzz(); + let backTo; + if (previous && previous.length) backTo = previous.pop(); + console.log("backTo = ", backTo); + switch (backTo) { + case "call": return showCall(call); + case "map": return showMap(map); + case "music": return showMusic(music); + case "alarm": return showAlarm(alarm); + case "text": + if (Bangle.MESSAGES.length) { + if (msgIdx < Bangle.MESSAGES.length) return showText(msgIdx); + else return showText(0); + } + default: + if (!timedOut) Bangle.MESSAGES.forEach((m) => {if (!m.new) m.show = false;}); + require("messages").write(Bangle.MESSAGES); + cleanup = _cleanup; + Bangle.showClock(); + } +}; // function goBack + +const newMessage = (type, msg) => { + filterMessages(); + // if (!previous.includes(active) && type != active) previous.push(active); + switch (type) { + case "text": + if (msg.t === "remove") { + let idx = Bangle.MESSAGES.findIndex(m => m.id === msg.id); + if (idx >= 0) Bangle.MESSAGES.splice(idx, 1); // remove 'remove' from Bangle.MESSAGES + idx = Bangle.MESSAGES.findIndex(m => m.id === msg.id && m.t !== "remove"); + if (active === "text" && buzzing && idx === msgIdx) require("messages").stopBuzz(); // if the message being viewed is removed stop buzzing + Bangle.MESSAGES = Bangle.MESSAGES.filter(m => m.id != msg.id); + require("messages").write(Bangle.MESSAGES); // write removal to flash + if (active === "text") { + if (idle) showText(msgIdx); // we are idle so updated messages right away + else haveNewMessage = true; // otherwise set new message flag and wait until idle + } + return; + } + let idx = Bangle.MESSAGES.findIndex(m => !m.handled); + if (idle) { // idle so show message right away + if (idx >= 0) { + for (let m of Bangle.MESSAGES) m.handled = true; // set all text messages as handled + setActive("text"); + return showText(idx); + } else { + setActive("text") + return showText(msgIdx); + } + } + else haveNewMessage = true; // otherwise set new message flag and wait until idle + break; + + case "call": + if (call && call.t === "remove") {call = undefined; goBack();} + if (call) {setActive("call"); showCall(call);} + break; + case "alarm": + if (alarm.new) {setActive("alarm"); showAlarm(alarm);} + break; + case "map": + if (map.new) {setActive("map"); showMap(map);} + break; + case "music": + if (music.new) {setActive("music"); showMusic(music);} + break; + } +}; +setListener("breakingnews", newMessage); + +const filterMessages = function() { + call = Bangle.MESSAGES.find(m => m.type === "call"); + alarm = Bangle.MESSAGES.find(m => m.type === "alarm"); + map = Bangle.MESSAGES.find(m => m.type === "map"); + music = Bangle.MESSAGES.find(m => m.type === "music"); + Bangle.MESSAGES = Bangle.MESSAGES.filter(m => m.type === "text"); +}; + +const showMessage = function() { + if (call) {setActive("call"); return showCall(call);} + else if (alarm && !alarm.handled) {setActive("alarm"); return showAlarm(alarm);} + else if (map && !map.handled) {setActive("map"); return showMap(map);} + else if (music && !music.handled) {setActive("music"); return showMusic(music);} + else { + idx = Bangle.MESSAGES.findIndex(m => !m.handled); + if (idx >= 0) { + for (let m of Bangle.MESSAGES) m.handled = true; // set all text messages as handled + setActive("text"); + return showText(idx); + } + } + goBack(); +}; + +// entry point +events.saveMessages = function() { + require("messages").write(Bangle.MESSAGES); +}; +E.on("kill", events.saveMessages); + +Bangle.loadWidgets(); +require("widget_utils").hide(); + if (!Bangle.MESSAGES || !Bangle.MESSAGES.length) { Bangle.MESSAGES = require("messages").getMessages(); } -if (!Bangle.MESSAGES.length) showNoMessages(); -if (Bangle.notify) { // this is set in messagecenter.notify.js +if (Bangle.notify) { // notification arrived that opened the app. This is set in messagecenter.notify.js buzzing = true; require("messages").buzz(Bangle.MESSAGES[0].src); delete Bangle.notify; + filterMessages(); + showMessage(); +} else { // user opened the app + if (!Bangle.MESSAGES.length) showNoMessages(); + else { + showText(); // show all messages + } } - -showText(true); +//} diff --git a/messagegui.lib.js b/messagegui.lib.js index 8b38ca6..bdf7000 100644 --- a/messagegui.lib.js +++ b/messagegui.lib.js @@ -5,23 +5,27 @@ exports.messageListener = function(type, msg) { if (msg.handled) return; if (global.__FILE__ === "messagecenter.app.js") inApp = true; if (!Bangle.MESSAGES || !Bangle.MESSAGES.length) Bangle.MESSAGES = require("messages").getMessages(msg); - if (type === "text") { - if (msg.t === "add") { - msg.show = true; - msg.new = true; - require("messages").apply(msg, Bangle.MESSAGES); - } else if (msg.t === "remove") { - Bangle.MESSAGES = Bangle.MESSAGES.filter(m => m.id != msg.id); - require("messages").write(Bangle.MESSAGES); // write removal to flash - if (!inApp) return; // don't open app for removal - } else if (msg.t === "modify") { - msg.show = true; - msg.new = true; - Bangle.MESSAGES = Bangle.MESSAGES.filter(m => m.id != msg.id); // remove old version of message - Bangle.MESSAGES.unshift(msg); // put modified message at top of list - } + msg.show = true; + msg.type = type; + if (msg.id === "call" && msg.t === "remove" && msg.cmd != "end") { + msg.t = "modify"; // not sure why messages module puts everything as remove except for "incoming" + msg.new = true; } + if (msg.t === "add") { + require("messages").apply(msg, Bangle.MESSAGES); + } else if (msg.t === "modify") { + Bangle.MESSAGES = Bangle.MESSAGES.filter(m => m.id != msg.id); // remove old version of message + Bangle.MESSAGES.unshift(msg); // put modified message at start of list + } else { + Bangle.MESSAGES.unshift(msg); // add new message to start of list + } + if (!inApp) { + if (msg.t === "remove") { + Bangle.MESSAGES = Bangle.MESSAGES.filter(m => m.id != msg.id); + require("messages").write(Bangle.MESSAGES); // write removal to flash + return; // don't open app for removal + } if (loadWillReset()) require("messages").write(Bangle.MESSAGES); Bangle.load("messagecenter.notify.js"); } else {