BangleApps/apps/messagelist/lib.js

247 lines
9.2 KiB
JavaScript
Raw Normal View History

2022-11-26 14:28:09 +00:00
// Handle incoming messages while the app is not loaded
// The messages app overrides Bangle.messageListener
// (placed in separate file, so we don't read this all at boot time)
exports.messageListener = function(type, msg) {
if (msg.handled || (global.__FILE__ && __FILE__.startsWith("messagelist."))) return; // already handled/app open
// clean up, in case previous message didn't load the app after all
if (exports.loadTimeout) clearTimeout(exports.loadTimeout);
delete exports.loadTimeout;
delete exports.buzz;
const quiet = () => (require("Storage").readJSON("setting.json", 1) || {}).quiet;
/**
* Quietly load the app for music/map, if not already loading
*/
function loadQuietly(msg) {
if (exports.loadTimeout) return; // already loading
exports.loadTimeout = setTimeout(function() {
Bangle.load("messagelist.app.js");
}, 500);
}
function loadNormal(msg) {
if (exports.loadTimeout) clearTimeout(exports.loadTimeout); // restart timeout
exports.loadTimeout = setTimeout(function() {
delete exports.loadTimeout;
// check there are still new messages (for #1362)
let messages = require("messages").getMessages(msg);
(Bangle.MESSAGES || []).forEach(m => require("messages").apply(m, messages));
if (!messages.some(m => m.new)) return; // don't use `status()`: also load for new music!
// if we're in a clock, or it's important, open app
if (Bangle.CLOCK || msg.important) {
if (exports.buzz) require("messages").buzz(msg.src);
Bangle.load("messagelist.app.js");
}
}, 500);
}
/**
* Mark message as handled, and save it for the app
*/
const handled = () => {
if (!Bangle.MESSAGES) Bangle.MESSAGES = [];
require("messages").apply(msg, Bangle.MESSAGES);
if (!Bangle.MESSAGES.length) delete Bangle.MESSAGES;
if (msg.t==="remove") require("messages").save(msg);
else msg.handled = true;
};
/**
* Write messages to flash after all, when not laoding the app
*/
const saveToFlash = () => {
(Bangle.MESSAGES||[]).forEach(m=>require("messages").save(m));
delete Bangle.MESSAGES;
}
switch(type) {
case "music":
if (!Bangle.CLOCK) return;
// only load app if we are playing, and we know which song
if (msg.state!=="play" || !msg.title) return;
if (exports.openMusic===undefined) {
// only read settings for first music message
exports.openMusic = !!(exports.settings().openMusic);
}
if (!exports.openMusic) return; // we don't care about music
if (quiet()) return;
msg.new = true;
handled();
return loadQuietly();
case "map":
handled();
if (msg.t!=="remove" && Bangle.CLOCK) loadQuietly();
else saveToFlash();
return;
case "text":
handled();
if (exports.settings().autoOpen===false) return saveToFlash();
if (quiet()) return saveToFlash();
if (msg.t!=="add" || !msg.new || !(Bangle.CLOCK || msg.important)) {
// not important enough to load the app
if (msg.t==="add" && msg.new) require("messages").buzz(msg);
return saveToFlash();
}
if (msg.t==="add" && msg.new) exports.buzz = true;
return loadNormal(msg);
case "alarm":
if (quiet()<2) return saveToFlash();
// fall through
case "call":
handled();
exports.buzz = true;
return loadNormal(msg);
// case "clearAll": do nothing
}
};
exports.settings = function() {
return Object.assign({
// Interface //
fontSize: 1,
onTap: 0, // [Message menu, Dismiss, Back, Nothing]
button: true,
// Behaviour //
vibrate: ":",
vibrateCalls: ":",
vibrateAlarms: ":",
repeat: 4,
vibrateTimeout: 60,
unreadTimeout: 60,
autoOpen: true,
// Music //
openMusic: true,
// no default: alwaysShowMusic (auto-enabled by app when music happens)
showAlbum: true,
musicButtons: false,
// Widget //
flash: true,
// showRead: false,
// Utils //
},
// fall back to default app settings if not set for messagelist
(require("Storage").readJSON("messages.settings.json", true) || {}),
(require("Storage").readJSON("messagelist.settings.json", true) || {}));
};
/**
* @param {string} icon Icon name
* @returns string Icon image string, for use with g.drawImage()
*/
exports.getIcon = function(icon) {
// TODO: icons should be 24x24px with 1bpp colors
switch(icon.toLowerCase()) {
// generic icons:
case "alert":
return atob("GBgBAAAAAP8AA//AD8PwHwD4HBg4ODwcODwccDwOcDwOYDwGYDwGYBgGYBgGcBgOcAAOOBgcODwcHDw4Hxj4D8PwA//AAP8AAAAA");
case "alarm":
case "alarmclockreceiver":
return atob("GBjBAP////8AAAAAAAACAEAHAOAefng5/5wTgcgHAOAOGHAMGDAYGBgYGBgYGBgYGBgYDhgYBxgMATAOAHAHAOADgcAB/4AAfgAAAAAAAAA=");
case "back": // TODO: 22x22
return atob("FhYBAAAAEAAAwAAHAAA//wH//wf//g///BwB+DAB4EAHwAAPAAA8AADwAAPAAB4AAHgAB+AH/wA/+AD/wAH8AA==");
case "calendar":
return atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B9m2B//+B//+Btm2B//+B//+Btm+B//+B//+A//8AAAAAAAAAAAAA==");
case "mail": // TODO: 28x18
case "sms message":
case "notification":
return atob("HBKBAD///8H///iP//8cf//j4//8f5//j/x/8//j/H//H4//4PB//EYj/44HH/Hw+P4//8fH//44///xH///g////A==");
case "map": // TODO: 25x25,
return atob("GRmBAAAAAAAAAAAAAAIAYAHx/wH//+D/+fhz75w/P/4f//8P//uH///D///h3f/w4P+4eO/8PHZ+HJ/nDu//g///wH+HwAYAIAAAAAAAAAAAAAA=");
case "menu":
return atob("GBiBAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAA==");
case "music": // TODO: 22x22
return atob("FhaBAH//+/////////////h/+AH/4Af/gB/+H3/7/f/v9/+/3/7+f/vB/w8H+Dwf4PD/x/////////////3//+A=");
case "nak": // TODO: 22x25
return atob("FhmBAA//wH//j//+P//8///7///v//+///7//////////////v//////////z//+D8AAPwAAfgAB+AAD4AAPgAAeAAB4AAHAAA==");
case "neg": // TODO: 22x22
return atob("FhaBADAAMeAB78AP/4B/fwP4/h/B/P4D//AH/4AP/AAf4AB/gAP/AB/+AP/8B/P4P4fx/A/v4B//AD94AHjAAMA=");
case "next":
return atob("GBiBAAAAAAAAAAAAAAwAcB8A+B+A+B/g+B/4+B/8+B//+B//+B//+B//+B//+B//+B/8+B/4+B/g+B+A+B8A+AwAcAAAAAAAAAAAAA==");
case "nophone": // TODO: 30x30
return atob("Hh6BAAAAAAGAAAAHAAAADgAAABwADwA4Af8AcA/8AOB/+AHH/+ADv/8AB//wAA/HAAAeAAACOAAADHAAAHjgAAPhwAAfg4AAfgcAAfwOAA/wHAA/wDgA/gBwA/gA4AfAAcAfAAOAGAAHAAAADgAAABgAAAAA");
case "ok": // TODO: 22x25
return atob("FhmBAAHAAAeAAB4AAPgAA+AAH4AAfgAD8AAPwAD//+//////////////7//////////////v//+///7///v//8///gf/+A//wA==");
case "pause":
return atob("GBiBAAAAAAAAAAAAAAOBwAfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AOBwAAAAAAAAAAAAA==");
case "phone": // TODO: 23x23
case "call":
return atob("FxeBABgAAPgAAfAAB/AAD+AAH+AAP8AAP4AAfgAA/AAA+AAA+AAA+AAB+AAB+AAB+OAB//AB//gB//gA//AA/8AAf4AAPAA=");
case "play":
return atob("GBiBAAAAAAAAAAAAAAcAAA+AAA/gAA/4AA/8AA//AA//wA//4A//8A//8A//4A//wA//AA/8AA/4AA/gAA+AAAcAAAAAAAAAAAAAAA==");
case "pos": // TODO: 25x20
return atob("GRSBAAAAAYAAAcAAAeAAAfAAAfAAAfAAAfAAAfAAAfBgAfA4AfAeAfAPgfAD4fAA+fAAP/AAD/AAA/AAAPAAADAAAA==");
case "previous":
return atob("GBiBAAAAAAAAAAAAAA4AMB8A+B8B+B8H+B8f+B8/+B//+B//+B//+B//+B//+B//+B8/+B8f+B8H+B8B+B8A+A4AMAAAAAAAAAAAAA==");
case "settings": // TODO: 20x20
return atob("FBSBAAAAAA8AAPABzzgf/4H/+A//APnwfw/n4H5+B+fw/g+fAP/wH/+B//gc84APAADwAAAA");
case "to do":
return atob("GBgBAAAAAAAAAAAwAAB4AAD8AAH+AAP/DAf/Hg//Px/+f7/8///4///wf//gP//AH/+AD/8AB/4AA/wAAfgAAPAAAGAAAAAAAAAA");
case "trash":
return atob("GBiBAAAAAAAAAAB+AA//8A//8AYAYAYAYAZmYAZmYAZmYAZmYAZmYAZmYAZmYAZmYAZmYAZmYAZmYAYAYAYAYAf/4AP/wAAAAAAAAA==");
case "unknown": // TODO: 30x30
return atob("Hh6BAAAAAAAAAAAAAAAAAAPwAAA/8AAB/+AAD//AAD4fAAHwPgAHwPgAAAPgAAAfAAAA/AAAD+AAAH8AAAHwAAAPgAAAPgAAAPgAAAAAAAAAAAAAAAAAAHAAAAPgAAAPgAAAPgAAAHAAAAAAAAAAAAAAAAAA");
case "unread": // TODO: 29x24
return atob("HRiBAAAAH4AAAf4AAB/4AAHz4AAfn4AA/Pz/5+fj/z8/j/n5/j/P//j/Pn3j+PPPx+P8fx+Pw/x+AF/B4A78RiP3xwOPvHw+Pcf/+Ox//+NH//+If//+B///+A==");
default: //should never happen
return exports.getIcon("unknown");
}
};
/**
* @param {string} icon Icon
* @returns {string} Color to use with g.setColor()
*/
exports.getColor = function(icon) {
switch(icon.toLowerCase()) {
// generic colors, using B2-safe colors
case "alert":
return "#ff0";
case "alarm":
return "#fff";
case "calendar":
return "#f00";
case "mail":
return "#ff0";
case "map":
return "#f0f";
case "music":
return "#f0f";
case "neg":
return "#f00";
case "notification":
return "#0ff";
case "phone":
case "call":
return "#0f0";
case "settings":
return "#000";
case "sms message":
return "#0ff";
case "trash":
return "#f00";
case "unknown":
return g.theme.fg;
case "unread":
return "#ff0";
default:
return g.theme.fg;
}
};
/**
* Launch GUI app with given message
* @param {object} msg
*/
exports.open = function(msg) {
if (msg && msg.id && !msg.show) {
// store which message to load
msg.show = 1;
}
Bangle.load((msg && msg.new && msg.id!=="music") ? "messagelist.new.js" : "messagelist.app.js");
};