forked from FOSS/BangleApps
247 lines
9.2 KiB
JavaScript
247 lines
9.2 KiB
JavaScript
// 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");
|
|
};
|