BangleApps/apps/widmsggrid/widget.js

103 lines
4.2 KiB
JavaScript

(function () {
if (global.MESSAGES) return; // don't load widget while in the app
let settings = require('Storage').readJSON("messages.settings.json", true) || {};
const s = {
flash: (settings.flash === undefined) ? true : !!settings.flash,
showRead: !!settings.showRead,
};
delete settings;
// widget name needs to be "messages": the library calls WIDGETS["messages'].hide()/show()
WIDGETS["messages"] = {
area: "tl", width: 0,
flash: s.flash,
showRead: s.showRead,
init: function() {
// runs on first draw
delete w.init; // don't run again
Bangle.on("touch", w.touch);
Bangle.on("message", w.listener);
w.listener(); // update status now
},
draw: function () {
if (w.init) w.init();
// If we had a setTimeout queued from the last time we were called, remove it
if (w.t) {
clearTimeout(w.t);
delete w.t;
}
if (!w.width || this.hidden) return;
const b = w.flash && w.status === "new" && ((Date.now() / 1000) & 1), // Blink(= inverse colors) on this second?
// show multiple icons in a grid, by scaling them down
cols = Math.ceil(Math.sqrt(w.srcs.length - 0.1)); // cols===rows, -0.1 to work around rounding error
g.reset().clearRect(w.x, w.y, w.x + w.width - 1, w.y + 24)
.setClipRect(w.x, w.y, w.x + w.width - 1, w.y + 24); // guard against oversized icons
let r = 0, c = 0; // row, column
const offset = pos => Math.floor(pos / cols * 24); // pixel offset for position in row/column
let icons = require("messageicons");
let defaultCol = icons.getColor("alert", {settings:settings});
w.srcs.forEach(src => {
const appColor = icons.getColor(src, {settings:settings,default:defaultCol});
let colors = [g.theme.bg, appColor];
if (b) {
if (colors[1] == g.theme.fg) colors = colors.reverse();
else colors[1] = g.theme.fg;
}
g.setColor(colors[1]).setBgColor(colors[0]);
g.drawImage(icons.getImage(src), w.x+offset(c), w.y+offset(r), { scale: 1 / cols });
if (++c >= cols) {
c = 0;
r++;
}
});
if (w.total > 1) {
// show total number of messages in bottom-right corner
g.reset();
if (w.total < 10) g.fillCircle(w.x + w.width - 5, w.y + 20, 4); // single digits get a round background, double digits fill their rectangle
g.setColor(g.theme.bg).setBgColor(g.theme.fg)
.setFont('6x8').setFontAlign(1, 1)
.drawString(w.total, w.x + w.width - 1, w.y + 24, w.total > 9);
}
if (w.flash && w.status === "new") w.t = setTimeout(w.draw, 1000); // schedule redraw while blinking
},
// show() and hide() are required by the "message" library!
show: function (m) {
delete w.hidden;
w.width = 24;
w.srcs = require("messages").getMessages(m)
.filter(m => !['call', 'map', 'music'].includes(m.id))
.filter(m => m.new || w.showRead)
.map(m => m.src);
w.total = w.srcs.length;
w.srcs = w.srcs.filter((src, i, uniq) => uniq.indexOf(src) === i); // keep unique entries only
Bangle.drawWidgets();
Bangle.setLCDPower(1); // turns screen on
}, hide: function () {
w.hidden = true;
w.width = 0;
w.srcs = [];
w.total = 0;
Bangle.drawWidgets();
}, touch: function (b, c) {
if (!w || !w.width) return; // widget not shown
if (process.env.HWVERSION < 2) {
// Bangle.js 1: open app when on clock we touch the side with widget
if (!Bangle.CLOCK) return;
const m = Bangle.appRect / 2;
if ((w.x < m && b !== 1) || (w.x > m && b !== 2)) return;
}
// Bangle.js 2: open app when touching the widget
else if (c.x < w.x || c.x > w.x + w.width || c.y < w.y || c.y > w.y + 24) return;
require("messages").openGUI();
}, listener: function (t,m) {
if (this.hidden) return;
w.status = require("messages").status(m);
if (w.status === "new" || (w.status === "old" && w.showRead)) w.show(m);
else w.hide();
delete w.hidden; // always set by w.hide(), but we checked it wasn't there before
}
};
delete s;
const w = WIDGETS["messages"];
Bangle.on("message", w.listener);
})();