diff --git a/apps/widmsggrid/ChangeLog b/apps/widmsggrid/ChangeLog new file mode 100644 index 000000000..4be6afb16 --- /dev/null +++ b/apps/widmsggrid/ChangeLog @@ -0,0 +1 @@ +0.01: New widget! \ No newline at end of file diff --git a/apps/widmsggrid/README.md b/apps/widmsggrid/README.md new file mode 100644 index 000000000..7c85d5c31 --- /dev/null +++ b/apps/widmsggrid/README.md @@ -0,0 +1,23 @@ +# Messages Grid Widget + +Widget that displays multiple notification icons in a grid. +The widget has a fixed size: if there are multiple notifications it uses smaller +icons. +It shows a single icon per application, so if you have two SMS messages, the +grid only has one SMS icon. +If there are multiple messages waiting, the total number is shown in the +bottom-right corner. + +Example: one SMS, one Signal, and two WhatsApp messages: +![screenshot](screenshot.png) + +## Installation +This widget needs the [`messages`](/?id=messages) app to handle notifications. + +## Settings +This widget uses the `Widget` settings from the `messages` app: + +### Widget +* `Flash icon` Toggle flashing of the widget icons. + +* `Widget messages` Not used by this widget, but you should select `Hide` to hide the default widget. \ No newline at end of file diff --git a/apps/widmsggrid/metadata.json b/apps/widmsggrid/metadata.json new file mode 100644 index 000000000..b624f5c23 --- /dev/null +++ b/apps/widmsggrid/metadata.json @@ -0,0 +1,16 @@ +{ + "id": "widmsggrid", + "name": "Messages Grid Widget", + "version": "0.01", + "description": "Widget that display notification icons in a grid", + "icon": "widget.png", + "type": "widget", + "dependencies": {"messages":"app"}, + "tags": "tool,system", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"widmsggrid.wid.js","url":"widget.js"} + ], + "screenshots": [{"url":"screenshot.png"}] +} diff --git a/apps/widmsggrid/screenshot.png b/apps/widmsggrid/screenshot.png new file mode 100644 index 000000000..b1cdb2a5a Binary files /dev/null and b/apps/widmsggrid/screenshot.png differ diff --git a/apps/widmsggrid/widget.js b/apps/widmsggrid/widget.js new file mode 100644 index 000000000..7c5882e6c --- /dev/null +++ b/apps/widmsggrid/widget.js @@ -0,0 +1,92 @@ +(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; + WIDGETS["msggrid"] = { + 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) 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 + w.srcs.forEach(src => { + const appColor = require("messages").getMessageImageCol(src, require("messages").getMessageImageCol("alert")); + let colors = [g.theme.bg, g.setColor(appColor).getColor()]; + 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(require("messages").getMessageImage(src, "alert"), 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: function () { + w.width = 24; + w.srcs = require("messages").getMessages() + .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.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; + load("messages.app.js"); + }, listener: function () { + w.status = require("messages").status(); + if (w.status === "new" || (w.status === "old" && w.showRead)) w.show(); + else w.hide(); + } + }; + delete s; + const w = WIDGETS["msggrid"]; +})(); \ No newline at end of file diff --git a/apps/widmsggrid/widget.png b/apps/widmsggrid/widget.png new file mode 100644 index 000000000..ce6e7b7ac Binary files /dev/null and b/apps/widmsggrid/widget.png differ