Merge pull request #3307 from halemmerich/messagesoverlay
messagesoverlay - Rendering and UI improvementsmaster
commit
90a793b966
|
|
@ -5,3 +5,8 @@
|
||||||
0.05: Fix the overlay keeping the LCD on
|
0.05: Fix the overlay keeping the LCD on
|
||||||
0.06: Better low memory handling
|
0.06: Better low memory handling
|
||||||
Fix first message beeing displayed again on unlock
|
Fix first message beeing displayed again on unlock
|
||||||
|
0.07: Adds settings
|
||||||
|
Automatic discard of oldest messages
|
||||||
|
Indicator for multiple messages in queue
|
||||||
|
Some optimization in the rendering code
|
||||||
|
Track handler changes done by background code
|
||||||
|
|
|
||||||
|
|
@ -2,23 +2,26 @@
|
||||||
|
|
||||||
This app handles the display of messages and message notifications as an overlay pop up.
|
This app handles the display of messages and message notifications as an overlay pop up.
|
||||||
|
|
||||||
It is a GUI replacement for the `messages` apps.
|
It is a GUI replacement for the `messagesgui` app.
|
||||||
|
|
||||||
Messages are ephemeral and not stored on the Bangle.
|
Messages are ephemeral and not stored on the Bangle.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Close app by tapping the X and scroll by swiping. The border of the pop up changes color if the Bangle is locked. The color depends on your currently active theme.
|
Close app by tapping the X and scroll by swiping. The title background of the pop up changes color if the Bangle is locked. The color depends on your currently active theme.
|
||||||
|
|
||||||
## Firmware hint
|
## Theme support
|
||||||
Current stable firmware draws incorrect colors for emojis. Nightly firmware builds correct this.
|
|
||||||
|
Using the system theme needs more RAM since it uses a 16 bit color buffer for normal message display. Selecting the "low RAM" theme reduces that to a 4 bit buffer.
|
||||||
|
16 bit buffer with a small message takes ~4K RAM blocks while 4 bit buffer only needs about 1.5K.
|
||||||
|
|
||||||
## Low memory mode
|
## Low memory mode
|
||||||
|
|
||||||
If free memory is below 2000 blocks, the overlay automatically only uses 1 bit depth. Default uses roundabout 1300 blocks, while low memory mode uses about 600.
|
If the overlay estimates that showing the next message would get under the configured minimum free memory limit it automatically only tries to use 1 bit depth. Low memory mode uses about 0.8K blocks plus memory needed for messages. If dropping to 1 bit depth is not enough the oldest messages are discarded to keep the overlay working.
|
||||||
|
|
||||||
## Creator
|
## Creator
|
||||||
|
|
||||||
[halemmerich](https://github.com/halemmerich)
|
[halemmerich](https://github.com/halemmerich)
|
||||||
|
|
||||||
Forked from messages_light by Rarder44
|
Forked from messages_light by Rarder44
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"autoclear": 30,
|
||||||
|
"border": 10,
|
||||||
|
"minfreemem": 2,
|
||||||
|
"systemTheme": true
|
||||||
|
}
|
||||||
|
|
@ -1,49 +1,69 @@
|
||||||
const MIN_FREE_MEM = 1000;
|
let lockListener;
|
||||||
const LOW_MEM = 2000;
|
let ovr;
|
||||||
const ovrx = 10;
|
let clearingTimeout;
|
||||||
const ovry = 10;
|
|
||||||
|
// Converts a espruino version to a semantiv versioning object
|
||||||
|
const toSemantic = function (v){
|
||||||
|
return {
|
||||||
|
major: v.substring(0,v.indexOf("v")),
|
||||||
|
minor: v.substring(v.indexOf("v") + 1, v.includes(".") ? v.indexOf(".") : v.length),
|
||||||
|
patch: v.includes(".") ? v.substring(v.indexOf(".") + 1, v.length) : 0
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const isNewer = function(espruinoVersion, baseVersion){
|
||||||
|
const s = toSemantic(espruinoVersion);
|
||||||
|
const b = toSemantic(baseVersion);
|
||||||
|
|
||||||
|
return s.major >= b.major &&
|
||||||
|
s.minor >= b.major &&
|
||||||
|
s.patch > b.patch;
|
||||||
|
};
|
||||||
|
|
||||||
|
let needsWorkaround;
|
||||||
|
|
||||||
|
let settings = Object.assign(
|
||||||
|
require('Storage').readJSON("messagesoverlay.default.json", true) || {},
|
||||||
|
require('Storage').readJSON("messagesoverlay.json", true) || {}
|
||||||
|
);
|
||||||
|
|
||||||
|
settings = Object.assign({
|
||||||
|
fontSmall:"6x8",
|
||||||
|
fontMedium:"6x15",
|
||||||
|
fontBig: "12x20"
|
||||||
|
}, settings);
|
||||||
|
|
||||||
|
const ovrx = settings.border;
|
||||||
|
const ovry = ovrx;
|
||||||
const ovrw = g.getWidth()-2*ovrx;
|
const ovrw = g.getWidth()-2*ovrx;
|
||||||
const ovrh = g.getHeight()-2*ovry;
|
const ovrh = g.getHeight()-2*ovry;
|
||||||
let _g = g;
|
|
||||||
|
|
||||||
let lockListener;
|
let LOG=()=>{};
|
||||||
let quiet;
|
//LOG = function() { print.apply(null, arguments);};
|
||||||
|
|
||||||
let LOG = function() {
|
const isQuiet = function(){
|
||||||
//print.apply(null, arguments);
|
return (require('Storage').readJSON('setting.json', 1) || {}).quiet;
|
||||||
};
|
|
||||||
|
|
||||||
let isQuiet = function(){
|
|
||||||
if (quiet == undefined) quiet = (require('Storage').readJSON('setting.json', 1) || {}).quiet;
|
|
||||||
return quiet;
|
|
||||||
};
|
|
||||||
|
|
||||||
let settings = {
|
|
||||||
fontSmall:"6x8",
|
|
||||||
fontMedium:"Vector:14",
|
|
||||||
fontBig:"Vector:20",
|
|
||||||
fontLarge:"Vector:30",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let eventQueue = [];
|
let eventQueue = [];
|
||||||
let callInProgress = false;
|
let callInProgress = false;
|
||||||
|
let buzzing = false;
|
||||||
|
|
||||||
let show = function(ovr){
|
const show = function(){
|
||||||
let img = ovr;
|
let img = ovr.asImage();
|
||||||
LOG("show", img.getBPP());
|
LOG("show", img.bpp);
|
||||||
if (ovr.getBPP() == 1) {
|
if (ovr.getBPP() == 1) {
|
||||||
img = ovr.asImage();
|
img.palette = new Uint16Array([g.theme.fg,g.theme.bg]);
|
||||||
img.palette = new Uint16Array([_g.theme.fg,_g.theme.bg]);
|
|
||||||
}
|
}
|
||||||
Bangle.setLCDOverlay(img, ovrx, ovry);
|
Bangle.setLCDOverlay(img, ovrx, ovry);
|
||||||
};
|
};
|
||||||
|
|
||||||
let manageEvent = function(ovr, event) {
|
const manageEvent = function(event) {
|
||||||
event.new = true;
|
event.new = true;
|
||||||
|
|
||||||
LOG("manageEvent");
|
LOG("manageEvent");
|
||||||
if (event.id == "call") {
|
if (event.id == "call") {
|
||||||
showCall(ovr, event);
|
showCall(event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (event.t) {
|
switch (event.t) {
|
||||||
|
|
@ -51,7 +71,7 @@ let manageEvent = function(ovr, event) {
|
||||||
eventQueue.unshift(event);
|
eventQueue.unshift(event);
|
||||||
|
|
||||||
if (!callInProgress)
|
if (!callInProgress)
|
||||||
showMessage(ovr, event);
|
showMessage(event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "modify": {
|
case "modify": {
|
||||||
|
|
@ -66,15 +86,15 @@ let manageEvent = function(ovr, event) {
|
||||||
eventQueue.unshift(event);
|
eventQueue.unshift(event);
|
||||||
|
|
||||||
if (!callInProgress)
|
if (!callInProgress)
|
||||||
showMessage(ovr, event);
|
showMessage(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "remove":
|
case "remove":
|
||||||
if (eventQueue.length == 0 && !callInProgress)
|
if (eventQueue.length == 0 && !callInProgress)
|
||||||
next(ovr);
|
next();
|
||||||
|
|
||||||
if (!callInProgress && eventQueue[0] !== undefined && eventQueue[0].id == event.id)
|
if (!callInProgress && eventQueue[0] !== undefined && eventQueue[0].id == event.id)
|
||||||
next(ovr);
|
next();
|
||||||
else
|
else
|
||||||
eventQueue = [];
|
eventQueue = [];
|
||||||
|
|
||||||
|
|
@ -82,7 +102,7 @@ let manageEvent = function(ovr, event) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let roundedRect = function(ovr, x,y,w,h,filled){
|
const roundedRect = function(x,y,w,h,filled){
|
||||||
var poly = [
|
var poly = [
|
||||||
x,y+4,
|
x,y+4,
|
||||||
x+4,y,
|
x+4,y,
|
||||||
|
|
@ -94,115 +114,153 @@ let roundedRect = function(ovr, x,y,w,h,filled){
|
||||||
x,y+h-5,
|
x,y+h-5,
|
||||||
x,y+4
|
x,y+4
|
||||||
];
|
];
|
||||||
|
if (filled){
|
||||||
|
let c = ovr.getColor();
|
||||||
|
ovr.setColor(ovr.getBgColor());
|
||||||
|
ovr.fillPoly(poly,true);
|
||||||
|
ovr.setColor(c);
|
||||||
|
}
|
||||||
ovr.drawPoly(poly,true);
|
ovr.drawPoly(poly,true);
|
||||||
if (filled) ovr.fillPoly(poly,true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let drawScreen = function(ovr, title, titleFont, src, iconcolor, icon){
|
const DIVIDER = 38;
|
||||||
ovr.setBgColor(ovr.theme.bg2);
|
|
||||||
ovr.clearRect(2,2,ovr.getWidth()-3,37);
|
const drawScreen = function(title, src, iconcolor, icon){
|
||||||
|
setColors(false);
|
||||||
|
|
||||||
|
drawBorder();
|
||||||
|
|
||||||
|
setColors(true);
|
||||||
|
ovr.clearRect(2,2,ovr.getWidth()-3, DIVIDER - 1);
|
||||||
|
|
||||||
ovr.setColor(ovr.theme.fg2);
|
|
||||||
ovr.setFont(settings.fontSmall);
|
ovr.setFont(settings.fontSmall);
|
||||||
ovr.setFontAlign(0,-1);
|
ovr.setFontAlign(0,-1);
|
||||||
|
|
||||||
let textCenter = (ovr.getWidth()+35-26)/2;
|
const textCenter = (ovr.getWidth()+34-24)/2-1;
|
||||||
|
|
||||||
if (src) {
|
const w = ovr.getWidth() - 35 - 26;
|
||||||
let shortened = src;
|
|
||||||
while (ovr.stringWidth(shortened) > ovr.getWidth()-80) shortened = shortened.substring(0,shortened.length-2);
|
if (title)
|
||||||
if (shortened.length != src.length) shortened += "...";
|
drawTitle(title, textCenter, w, 8, DIVIDER - 8, 0);
|
||||||
ovr.drawString(shortened, textCenter, 2);
|
|
||||||
|
if (src)
|
||||||
|
drawSource(src, textCenter, w, 2, -1);
|
||||||
|
|
||||||
|
if (ovr.getBPP() > 1) {
|
||||||
|
let old = ovr.getBgColor();
|
||||||
|
ovr.setBgColor("#888");
|
||||||
|
roundedRect(4, 5, 30, 30,true);
|
||||||
|
ovr.setBgColor(old);
|
||||||
|
old = ovr.getColor();
|
||||||
|
ovr.setColor(iconcolor);
|
||||||
|
ovr.drawImage(icon,7,8);
|
||||||
|
ovr.setColor(old);
|
||||||
|
} else {
|
||||||
|
roundedRect(4, 5, 30, 30,true);
|
||||||
|
ovr.drawImage(icon,7,8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
roundedRect(ovr.getWidth()-26,5,22,30,true);
|
||||||
ovr.setFontAlign(0,0);
|
ovr.setFontAlign(0,0);
|
||||||
ovr.setFont(titleFont);
|
|
||||||
if (title) ovr.drawString(title, textCenter, 38/2 + 5);
|
|
||||||
|
|
||||||
ovr.setColor(ovr.theme.fg2);
|
|
||||||
|
|
||||||
ovr.setFont(settings.fontMedium);
|
|
||||||
roundedRect(ovr, ovr.getWidth()-26,5,22,30,false);
|
|
||||||
ovr.setFont("Vector:16");
|
ovr.setFont("Vector:16");
|
||||||
ovr.drawString("X",ovr.getWidth()-14,21);
|
ovr.drawString("X",ovr.getWidth()-14,20);
|
||||||
|
|
||||||
ovr.setColor("#888");
|
|
||||||
roundedRect(ovr, 5,5,30,30,true);
|
|
||||||
ovr.setColor(ovr.getBPP() != 1 ? iconcolor : ovr.theme.bg2);
|
|
||||||
ovr.drawImage(icon,8,8);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let showMessage = function(ovr, msg) {
|
const drawSource = function(src, center, w, y, align) {
|
||||||
LOG("showMessage");
|
ovr.setFont(settings.fontSmall);
|
||||||
ovr.setBgColor(ovr.theme.bg);
|
while (ovr.stringWidth(src) > w) src = src.substring(0,src.length-2);
|
||||||
|
if (src.length != src.length) src += "...";
|
||||||
|
ovr.setFontAlign(0,align);
|
||||||
|
ovr.drawString(src, center, y);
|
||||||
|
};
|
||||||
|
|
||||||
if (typeof msg.CanscrollDown === "undefined")
|
const drawTitle = function(title, center, w, y, h) {
|
||||||
msg.CanscrollDown = false;
|
let size = 30;
|
||||||
if (typeof msg.CanscrollUp === "undefined")
|
|
||||||
msg.CanscrollUp = false;
|
|
||||||
|
|
||||||
// Normal text message display
|
while (ovr.setFont("Vector:" + size).stringWidth(title) > w){
|
||||||
let title = msg.title,
|
size -= 2;
|
||||||
titleFont = settings.fontLarge,
|
if (size < 14){
|
||||||
lines;
|
ovr.setFont(settings.fontMedium);
|
||||||
if (title) {
|
break;
|
||||||
let w = ovr.getWidth() - 35 - 26;
|
|
||||||
if (ovr.setFont(titleFont).stringWidth(title) > w)
|
|
||||||
titleFont = settings.fontMedium;
|
|
||||||
if (ovr.setFont(titleFont).stringWidth(title) > w) {
|
|
||||||
lines = ovr.wrapString(title, w);
|
|
||||||
title = (lines.length > 2) ? lines.slice(0, 2).join("\n") + "..." : lines.join("\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drawScreen(ovr, title, titleFont, msg.src || /*LANG*/ "Message", require("messageicons").getColor(msg), require("messageicons").getImage(msg));
|
let dh;
|
||||||
|
let a;
|
||||||
|
if (ovr.stringWidth(title) > w) {
|
||||||
|
let ws = ovr.wrapString(title, w);
|
||||||
|
if (ws.length >= 2 && ovr.stringWidth(ws[1]) > w - 8){
|
||||||
|
ws[1] = ws[1].substring(0, ws[1].length - 2);
|
||||||
|
ws[1] += "...";
|
||||||
|
}
|
||||||
|
title = ws.slice(0, 2).join("\n");
|
||||||
|
|
||||||
|
a = -1;
|
||||||
|
dh = y + 2;
|
||||||
|
} else {
|
||||||
|
a = 0;
|
||||||
|
dh = y + h/2;
|
||||||
|
}
|
||||||
|
ovr.setFontAlign(0, a);
|
||||||
|
ovr.drawString(title, center, dh);
|
||||||
|
};
|
||||||
|
|
||||||
|
const setColors = function(lockRelevant) {
|
||||||
|
if (lockRelevant && !Bangle.isLocked()){
|
||||||
|
ovr.setColor(ovr.theme.fg2);
|
||||||
|
ovr.setBgColor(ovr.theme.bg2);
|
||||||
|
} else {
|
||||||
|
ovr.setColor(ovr.theme.fg);
|
||||||
|
ovr.setBgColor(ovr.theme.bg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const showMessage = function(msg) {
|
||||||
|
LOG("showMessage");
|
||||||
|
|
||||||
|
ovr.setClipRect(0,0,ovr.getWidth(),ovr.getHeight());
|
||||||
|
|
||||||
|
drawScreen(msg.title, msg.src || /*LANG*/ "Message", require("messageicons").getColor(msg), require("messageicons").getImage(msg));
|
||||||
|
|
||||||
|
|
||||||
|
if (!Bangle.isLocked()){
|
||||||
|
ovr.setColor(ovr.theme.fg);
|
||||||
|
ovr.setBgColor(ovr.theme.bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawMessage(msg);
|
||||||
|
|
||||||
if (!isQuiet() && msg.new) {
|
if (!isQuiet() && msg.new) {
|
||||||
msg.new = false;
|
msg.new = false;
|
||||||
Bangle.buzz();
|
if (!buzzing){
|
||||||
|
buzzing = true;
|
||||||
|
Bangle.buzz().then(()=>{setTimeout(()=>{buzzing = false;},2000);});
|
||||||
|
}
|
||||||
|
Bangle.setLCDPower(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawMessage(ovr, msg);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let drawBorder = function(img) {
|
const drawBorder = function() {
|
||||||
LOG("drawBorder", isQuiet());
|
LOG("drawBorder", isQuiet());
|
||||||
if (img) ovr=img;
|
|
||||||
if (Bangle.isLocked())
|
|
||||||
ovr.setColor(ovr.theme.fgH);
|
|
||||||
else
|
|
||||||
ovr.setColor(ovr.theme.fg);
|
|
||||||
ovr.drawRect(0,0,ovr.getWidth()-1,ovr.getHeight()-1);
|
ovr.drawRect(0,0,ovr.getWidth()-1,ovr.getHeight()-1);
|
||||||
ovr.drawRect(1,1,ovr.getWidth()-2,ovr.getHeight()-2);
|
ovr.drawRect(1,1,ovr.getWidth()-2,ovr.getHeight()-2);
|
||||||
show(ovr);
|
ovr.drawRect(2,DIVIDER,ovr.getWidth()-2,DIVIDER+1);
|
||||||
|
show();
|
||||||
};
|
};
|
||||||
|
|
||||||
let showCall = function(ovr, msg) {
|
const showCall = function(msg) {
|
||||||
LOG("showCall");
|
LOG("showCall");
|
||||||
LOG(msg);
|
LOG(msg);
|
||||||
|
|
||||||
if (msg.t == "remove") {
|
if (msg.t == "remove") {
|
||||||
LOG("hide call screen");
|
LOG("hide call screen");
|
||||||
next(ovr); //dont shift
|
next(); //dont shift
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
callInProgress = true;
|
callInProgress = true;
|
||||||
|
|
||||||
let title = msg.title,
|
drawScreen(msg.title, msg.src || /*LANG*/ "Message", require("messageicons").getColor(msg), require("messageicons").getImage(msg));
|
||||||
titleFont = settings.fontLarge,
|
|
||||||
lines;
|
|
||||||
if (title) {
|
|
||||||
let w = ovr.getWidth() - 35 -26;
|
|
||||||
if (ovr.setFont(titleFont).stringWidth(title) > w)
|
|
||||||
titleFont = settings.fontMedium;
|
|
||||||
if (ovr.setFont(titleFont).stringWidth(title) > w) {
|
|
||||||
lines = ovr.wrapString(title, w);
|
|
||||||
title = (lines.length > 2) ? lines.slice(0, 2).join("\n") + "..." : lines.join("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
drawScreen(ovr, title, titleFont, msg.src || /*LANG*/ "Message", require("messageicons").getColor(msg), require("messageicons").getImage(msg));
|
|
||||||
|
|
||||||
stopCallBuzz();
|
stopCallBuzz();
|
||||||
if (!isQuiet()) {
|
if (!isQuiet()) {
|
||||||
|
|
@ -216,10 +274,10 @@ let showCall = function(ovr, msg) {
|
||||||
Bangle.buzz(500);
|
Bangle.buzz(500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drawMessage(ovr, msg);
|
drawMessage(msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
let next = function(ovr) {
|
const next = function() {
|
||||||
LOG("next");
|
LOG("next");
|
||||||
stopCallBuzz();
|
stopCallBuzz();
|
||||||
|
|
||||||
|
|
@ -230,203 +288,379 @@ let next = function(ovr) {
|
||||||
if (eventQueue.length == 0) {
|
if (eventQueue.length == 0) {
|
||||||
LOG("no element in queue - closing");
|
LOG("no element in queue - closing");
|
||||||
cleanup();
|
cleanup();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
showMessage(ovr, eventQueue[0]);
|
showMessage(eventQueue[0]);
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
let callBuzzTimer = null;
|
let callBuzzTimer = null;
|
||||||
let stopCallBuzz = function() {
|
const stopCallBuzz = function() {
|
||||||
if (callBuzzTimer) {
|
if (callBuzzTimer) {
|
||||||
clearInterval(callBuzzTimer);
|
clearInterval(callBuzzTimer);
|
||||||
callBuzzTimer = undefined;
|
callBuzzTimer = undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let drawTriangleUp = function(ovr) {
|
const drawTriangleUp = function() {
|
||||||
ovr.reset();
|
ovr.fillPoly([ovr.getWidth()-10, 46,ovr.getWidth()-15, 56,ovr.getWidth()-5, 56]);
|
||||||
ovr.fillPoly([ovr.getWidth()-9, 46,ovr.getWidth()-14, 56,ovr.getWidth()-4, 56]);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let drawTriangleDown = function(ovr) {
|
const drawTriangleDown = function() {
|
||||||
ovr.reset();
|
ovr.fillPoly([ovr.getWidth()-10, ovr.getHeight()-6, ovr.getWidth()-15, ovr.getHeight()-16, ovr.getWidth()-5, ovr.getHeight()-16]);
|
||||||
ovr.fillPoly([ovr.getWidth()-9, ovr.getHeight()-6, ovr.getWidth()-14, ovr.getHeight()-16, ovr.getWidth()-4, ovr.getHeight()-16]);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let linesScroll = 6;
|
|
||||||
|
|
||||||
let scrollUp = function(ovr) {
|
const scrollUp = function() {
|
||||||
msg = eventQueue[0];
|
const msg = eventQueue[0];
|
||||||
LOG("up", msg);
|
LOG("up", msg);
|
||||||
if (typeof msg.FirstLine === "undefined")
|
|
||||||
msg.FirstLine = 0;
|
|
||||||
if (typeof msg.CanscrollUp === "undefined")
|
|
||||||
msg.CanscrollUp = false;
|
|
||||||
|
|
||||||
if (!msg.CanscrollUp) return;
|
if (!msg.CanscrollUp) return;
|
||||||
|
|
||||||
msg.FirstLine = msg.FirstLine > 0 ? msg.FirstLine - linesScroll : 0;
|
msg.FirstLine = msg.FirstLine > 0 ? msg.FirstLine - 1 : 0;
|
||||||
|
drawMessage(msg);
|
||||||
drawMessage(ovr, msg);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let scrollDown = function(ovr) {
|
const scrollDown = function() {
|
||||||
msg = eventQueue[0];
|
const msg = eventQueue[0];
|
||||||
LOG("down", msg);
|
LOG("down", msg);
|
||||||
if (typeof msg.FirstLine === "undefined")
|
|
||||||
msg.FirstLine = 0;
|
|
||||||
if (typeof msg.CanscrollDown === "undefined")
|
|
||||||
msg.CanscrollDown = false;
|
|
||||||
|
|
||||||
if (!msg.CanscrollDown) return;
|
if (!msg.CanscrollDown) return;
|
||||||
|
|
||||||
msg.FirstLine = msg.FirstLine + linesScroll;
|
msg.FirstLine = msg.FirstLine + 1;
|
||||||
drawMessage(ovr, msg);
|
drawMessage(msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
let drawMessage = function(ovr, msg) {
|
const drawMessage = function(msg) {
|
||||||
let MyWrapString = function(str, maxWidth) {
|
setColors(false);
|
||||||
|
const getStringHeight = function(str){
|
||||||
|
"jit";
|
||||||
|
const metrics = ovr.stringMetrics(str);
|
||||||
|
if (needsWorkaround === undefined)
|
||||||
|
needsWorkaround = isNewer("2v21.13", process.version);
|
||||||
|
if (needsWorkaround && metrics.maxImageHeight > 16)
|
||||||
|
metrics.maxImageHeight = metrics.height;
|
||||||
|
return Math.max(metrics.height, metrics.maxImageHeight);
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapString = function(str, maxWidth) {
|
||||||
str = str.replace("\r\n", "\n").replace("\r", "\n");
|
str = str.replace("\r\n", "\n").replace("\r", "\n");
|
||||||
return ovr.wrapString(str, maxWidth);
|
return ovr.wrapString(str, maxWidth);
|
||||||
};
|
};
|
||||||
|
const wrappedStringHeight = function(strArray){
|
||||||
|
let r = 0;
|
||||||
|
strArray.forEach((line, i) => {
|
||||||
|
r += getStringHeight(line);
|
||||||
|
});
|
||||||
|
return r;
|
||||||
|
};
|
||||||
|
|
||||||
if (typeof msg.FirstLine === "undefined") msg.FirstLine = 0;
|
if (msg.FirstLine === undefined) msg.FirstLine = 0;
|
||||||
|
|
||||||
let bodyFont = typeof msg.bodyFont === "undefined" ? settings.fontMedium : msg.bodyFont;
|
const padding = eventQueue.length > 1 ? (eventQueue.length > 3 ? 7 : 5) : 3;
|
||||||
let Padding = 3;
|
|
||||||
if (typeof msg.lines === "undefined") {
|
const yText = DIVIDER+2;
|
||||||
|
let yLine = yText + 4;
|
||||||
|
|
||||||
|
ovr.setClipRect(2, yText, ovr.getWidth() - 3, ovr.getHeight() - 3);
|
||||||
|
|
||||||
|
const maxTextHeight = ovr.getHeight() - yLine - padding + 2;
|
||||||
|
|
||||||
|
if (!msg.lines) {
|
||||||
|
let bodyFont = settings.fontBig;
|
||||||
ovr.setFont(bodyFont);
|
ovr.setFont(bodyFont);
|
||||||
msg.lines = MyWrapString(msg.body, ovr.getWidth() - (Padding * 2));
|
msg.lines = wrapString(msg.body, ovr.getWidth() - 4 - padding);
|
||||||
if (msg.lines.length <= 2) {
|
|
||||||
bodyFont = ovr.getFonts().includes("Vector") ? "Vector:20" : "6x8:3";
|
if (wrappedStringHeight(msg.lines) > maxTextHeight) {
|
||||||
|
bodyFont = settings.fontMedium;
|
||||||
ovr.setFont(bodyFont);
|
ovr.setFont(bodyFont);
|
||||||
msg.lines = MyWrapString(msg.body, ovr.getWidth() - (Padding * 2));
|
msg.lines = wrapString(msg.body, ovr.getWidth() - 4 - padding);
|
||||||
msg.bodyFont = bodyFont;
|
|
||||||
}
|
}
|
||||||
|
msg.bodyFont = bodyFont;
|
||||||
|
msg.lineHeights = [];
|
||||||
|
msg.lines.forEach((line, i) => {
|
||||||
|
msg.lineHeights[i] = getStringHeight(line);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let NumLines = 7;
|
LOG("Prepared message", msg);
|
||||||
|
|
||||||
let linesToPrint = (msg.lines.length > NumLines) ? msg.lines.slice(msg.FirstLine, msg.FirstLine + NumLines) : msg.lines;
|
ovr.setFont(msg.bodyFont);
|
||||||
|
ovr.clearRect(2, yText, ovr.getWidth()-3, ovr.getHeight()-3);
|
||||||
|
|
||||||
let yText = 40;
|
let xText = 4;
|
||||||
|
|
||||||
ovr.setBgColor(ovr.theme.bg);
|
if (msg.bodyFont == settings.fontBig) {
|
||||||
ovr.setColor(ovr.theme.fg);
|
|
||||||
ovr.clearRect(2, yText, ovrw-3, ovrh-3);
|
|
||||||
let xText = Padding;
|
|
||||||
yText += Padding;
|
|
||||||
ovr.setFont(bodyFont);
|
|
||||||
let HText = ovr.getFontHeight();
|
|
||||||
|
|
||||||
yText = ((ovrh - yText) / 2) - (linesToPrint.length * HText / 2) + yText;
|
|
||||||
|
|
||||||
if (linesToPrint.length <= 3) {
|
|
||||||
ovr.setFontAlign(0, -1);
|
ovr.setFontAlign(0, -1);
|
||||||
xText = ovr.getWidth() / 2;
|
xText = Math.round(ovr.getWidth() / 2 - (padding - 3) / 2) + 1;
|
||||||
} else
|
yLine = (ovr.getHeight() + yLine) / 2 - (wrappedStringHeight(msg.lines) / 2);
|
||||||
|
ovr.drawString(msg.lines.join("\n"), xText, yLine);
|
||||||
|
} else {
|
||||||
ovr.setFontAlign(-1, -1);
|
ovr.setFontAlign(-1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentLine = msg.FirstLine;
|
||||||
|
|
||||||
linesToPrint.forEach((line, i) => {
|
let drawnHeight = 0;
|
||||||
ovr.drawString(line, xText, yText + HText * i);
|
|
||||||
});
|
while(drawnHeight < maxTextHeight && msg.lines.length > currentLine) {
|
||||||
|
const lineHeight = msg.lineHeights[currentLine];
|
||||||
|
ovr.drawString(msg.lines[currentLine], xText, yLine + drawnHeight);
|
||||||
|
drawnHeight += lineHeight;
|
||||||
|
currentLine++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventQueue.length > 1){
|
||||||
|
ovr.drawLine(ovr.getWidth()-4,ovr.getHeight()/2,ovr.getWidth()-4,ovr.getHeight()-4);
|
||||||
|
ovr.drawLine(ovr.getWidth()/2,ovr.getHeight()-4,ovr.getWidth()-4,ovr.getHeight()-4);
|
||||||
|
}
|
||||||
|
if (eventQueue.length > 3){
|
||||||
|
ovr.drawLine(ovr.getWidth()-6,ovr.getHeight()*0.6,ovr.getWidth()-6,ovr.getHeight()-6);
|
||||||
|
ovr.drawLine(ovr.getWidth()*0.6,ovr.getHeight()-6,ovr.getWidth()-6,ovr.getHeight()-6);
|
||||||
|
}
|
||||||
|
|
||||||
if (msg.FirstLine != 0) {
|
if (msg.FirstLine != 0) {
|
||||||
msg.CanscrollUp = true;
|
msg.CanscrollUp = true;
|
||||||
drawTriangleUp(ovr);
|
drawTriangleUp();
|
||||||
} else
|
} else
|
||||||
msg.CanscrollUp = false;
|
msg.CanscrollUp = false;
|
||||||
|
|
||||||
if (msg.FirstLine + linesToPrint.length < msg.lines.length) {
|
if (currentLine < msg.lines.length) {
|
||||||
msg.CanscrollDown = true;
|
msg.CanscrollDown = true;
|
||||||
drawTriangleDown(ovr);
|
drawTriangleDown();
|
||||||
} else
|
} else
|
||||||
msg.CanscrollDown = false;
|
msg.CanscrollDown = false;
|
||||||
show(ovr);
|
|
||||||
if (!isQuiet()) Bangle.setLCDPower(1);
|
show();
|
||||||
};
|
};
|
||||||
|
|
||||||
let getSwipeHandler = function(ovr){
|
const getDragHandler = function(){
|
||||||
return (lr, ud) => {
|
return (e) => {
|
||||||
if (ud == 1) {
|
if (e.dy > 0) {
|
||||||
scrollUp(ovr);
|
scrollUp();
|
||||||
} else if (ud == -1){
|
} else if (e.dy < 0){
|
||||||
scrollDown(ovr);
|
scrollDown();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
let getTouchHandler = function(ovr){
|
const getTouchHandler = function(){
|
||||||
return (_, xy) => {
|
return (_, xy) => {
|
||||||
if (xy.y < ovry + 40){
|
if (xy.y < ovry + DIVIDER){
|
||||||
next(ovr);
|
next();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
let restoreHandler = function(event){
|
const EVENTS=["touch", "drag", "swipe"];
|
||||||
LOG("Restore", event, backup[event]);
|
|
||||||
Bangle.removeAllListeners(event);
|
let hasBackup = false;
|
||||||
Bangle["#on" + event]=backup[event];
|
|
||||||
backup[event] = undefined;
|
const origOn = Bangle.on;
|
||||||
|
const backupOn = function(event, handler){
|
||||||
|
if (EVENTS.includes(event)){
|
||||||
|
if (!backup[event])
|
||||||
|
backup[event] = [];
|
||||||
|
backup[event].push(handler);
|
||||||
|
}
|
||||||
|
else origOn.call(Bangle, event, handler);
|
||||||
};
|
};
|
||||||
|
|
||||||
let backupHandler = function(event){
|
const origClearWatch = clearWatch;
|
||||||
if (backupDone) return; // do not backup, overlay is already up
|
const backupClearWatch = function(w) {
|
||||||
backup[event] = Bangle["#on" + event];
|
if (w)
|
||||||
LOG("Backed up", backup[event]);
|
backup.watches.filter((e)=>e.index != w);
|
||||||
Bangle.removeAllListeners(event);
|
else
|
||||||
|
backup.watches = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
let cleanup = function(){
|
const origSetWatch = setWatch;
|
||||||
|
const backupSetWatch = function(){
|
||||||
|
if (!backup.watches)
|
||||||
|
backup.watches = [];
|
||||||
|
LOG("backup for watch", arguments);
|
||||||
|
let i = backup.watches.map((e)=>e.index).sort().pop() + 1;
|
||||||
|
backup.watches.push({index:i, args:arguments});
|
||||||
|
return i;
|
||||||
|
};
|
||||||
|
|
||||||
|
const origRemove = Bangle.removeListener;
|
||||||
|
const backupRemove = function(event, handler){
|
||||||
|
if (EVENTS.includes(event) && backup[event]){
|
||||||
|
LOG("backup for " + event + ": " + backup[event]);
|
||||||
|
backup[event] = backup[event].filter(e=>e!==handler);
|
||||||
|
}
|
||||||
|
else origRemove.call(Bangle, event, handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
const origRemoveAll = Bangle.removeAllListeners;
|
||||||
|
const backupRemoveAll = function(event){
|
||||||
|
if (backup[event])
|
||||||
|
backup[event] = undefined;
|
||||||
|
origRemoveAll.call(Bangle);
|
||||||
|
};
|
||||||
|
|
||||||
|
const restoreHandlers = function(){
|
||||||
|
if (!hasBackup){
|
||||||
|
LOG("No backup available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const event of EVENTS){
|
||||||
|
LOG("Restore", backup[event]);
|
||||||
|
origRemoveAll.call(Bangle, event);
|
||||||
|
if (backup[event] && backup[event].length == 1)
|
||||||
|
backup[event] = backup[event][0];
|
||||||
|
Bangle["#on" + event]=backup[event];
|
||||||
|
backup[event] = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backup.watches){
|
||||||
|
toRemove = [];
|
||||||
|
|
||||||
|
origClearWatch.call(global);
|
||||||
|
|
||||||
|
for(let i = 0; i < backup.watches.length; i++){
|
||||||
|
let w = backup.watches[i];
|
||||||
|
LOG("Restoring watch", w);
|
||||||
|
if (w) {
|
||||||
|
origSetWatch.apply(global, w);
|
||||||
|
} else {
|
||||||
|
toRemove.push(i+1);
|
||||||
|
origSetWatch.call(global, ()=>{}, BTN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG("Remove watches", toRemove, global["\xff"].watches);
|
||||||
|
for(let c of toRemove){
|
||||||
|
origClearWatch.call(global, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global.setWatch = origSetWatch;
|
||||||
|
global.clearWatch = origClearWatch;
|
||||||
|
Bangle.on = origOn;
|
||||||
|
Bangle.removeListener = origRemove;
|
||||||
|
Bangle.removeAllListeners = origRemoveAll;
|
||||||
|
|
||||||
|
hasBackup = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const backupHandlers = function(){
|
||||||
|
if (hasBackup){
|
||||||
|
LOG("Backup already exists");
|
||||||
|
return false; // do not backup, overlay is already up
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const event of EVENTS){
|
||||||
|
backup[event] = Bangle["#on" + event];
|
||||||
|
if (typeof backup[event] == "function")
|
||||||
|
backup[event] = [ backup[event] ];
|
||||||
|
LOG("Backed up", backup[event], event);
|
||||||
|
Bangle.removeAllListeners(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
backup.watches = [];
|
||||||
|
|
||||||
|
for (let i = 1; i < global["\xff"].watches.length; i++){
|
||||||
|
let w = global["\xff"].watches[i];
|
||||||
|
LOG("Transform watch", w);
|
||||||
|
if (w) {
|
||||||
|
w = [
|
||||||
|
w.callback,
|
||||||
|
w.pin,
|
||||||
|
w
|
||||||
|
];
|
||||||
|
delete w[2].callback;
|
||||||
|
delete w[2].pin;
|
||||||
|
w[2].debounce = Math.round(w[2].debounce / 1048.576);
|
||||||
|
} else {
|
||||||
|
w = null;
|
||||||
|
}
|
||||||
|
LOG("Transformed to", w);
|
||||||
|
backup.watches.push(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG("Backed up watches", backup.watches);
|
||||||
|
clearWatch();
|
||||||
|
|
||||||
|
global.setWatch = backupSetWatch;
|
||||||
|
global.clearWatch = backupClearWatch;
|
||||||
|
Bangle.on = backupOn;
|
||||||
|
Bangle.removeListener = backupRemove;
|
||||||
|
Bangle.removeAllListeners = backupRemoveAll;
|
||||||
|
|
||||||
|
hasBackup = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const cleanup = function(){
|
||||||
if (lockListener) {
|
if (lockListener) {
|
||||||
Bangle.removeListener("lock", lockListener);
|
Bangle.removeListener("lock", lockListener);
|
||||||
lockListener = undefined;
|
lockListener = undefined;
|
||||||
}
|
}
|
||||||
restoreHandler("touch");
|
restoreHandlers();
|
||||||
restoreHandler("swipe");
|
|
||||||
restoreHandler("drag");
|
|
||||||
|
|
||||||
Bangle.setLCDOverlay();
|
Bangle.setLCDOverlay();
|
||||||
backupDone = false;
|
|
||||||
ovr = undefined;
|
ovr = undefined;
|
||||||
quiet = undefined;
|
quiet = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
let backup = {};
|
const backup = {};
|
||||||
|
|
||||||
let backupDone = false;
|
const main = function(event) {
|
||||||
|
LOG("Main", event.t);
|
||||||
let main = function(ovr, event) {
|
const didBackup = backupHandlers();
|
||||||
LOG("Main", event, settings);
|
|
||||||
|
|
||||||
if (!lockListener) {
|
if (!lockListener) {
|
||||||
lockListener = function (){
|
lockListener = function (e){
|
||||||
drawBorder();
|
updateClearingTimeout();
|
||||||
|
showMessage(eventQueue[0]);
|
||||||
};
|
};
|
||||||
Bangle.on('lock', lockListener);
|
LOG("Add overlay lock handlers");
|
||||||
|
origOn.call(Bangle, 'lock', lockListener);
|
||||||
}
|
}
|
||||||
backupHandler("touch");
|
|
||||||
backupHandler("swipe");
|
if (didBackup){
|
||||||
backupHandler("drag");
|
LOG("Add overlay UI handlers");
|
||||||
if (!backupDone){
|
origOn.call(Bangle, 'touch', getTouchHandler(ovr));
|
||||||
Bangle.on('touch', getTouchHandler(ovr));
|
origOn.call(Bangle, 'drag', getDragHandler(ovr));
|
||||||
Bangle.on('swipe', getSwipeHandler(ovr));
|
|
||||||
}
|
}
|
||||||
backupDone=true;
|
|
||||||
|
|
||||||
if (event !== undefined){
|
if (event !== undefined){
|
||||||
drawBorder(ovr);
|
manageEvent(event);
|
||||||
manageEvent(ovr, event);
|
|
||||||
} else {
|
} else {
|
||||||
LOG("No event given");
|
LOG("No event given");
|
||||||
cleanup();
|
cleanup();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let ovr;
|
const updateClearingTimeout = ()=>{
|
||||||
|
LOG("updateClearingTimeout");
|
||||||
|
if (settings.autoclear <= 0)
|
||||||
|
return;
|
||||||
|
LOG("Remove clearing timeout", clearingTimeout);
|
||||||
|
if (clearingTimeout) clearTimeout(clearingTimeout);
|
||||||
|
if (Bangle.isLocked()){
|
||||||
|
LOG("Set new clearing timeout");
|
||||||
|
clearingTimeout = setTimeout(()=>{
|
||||||
|
LOG("setNewTimeout");
|
||||||
|
const event = eventQueue.pop();
|
||||||
|
if (event)
|
||||||
|
showMessage(event);
|
||||||
|
if (eventQueue.length > 0){
|
||||||
|
LOG("still got elements");
|
||||||
|
updateClearingTimeout();
|
||||||
|
} else {
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
}, settings.autoclear * 1000);
|
||||||
|
} else {
|
||||||
|
clearingTimeout = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
exports.message = function(type, event) {
|
exports.message = function(type, event) {
|
||||||
LOG("Got message", type, event);
|
LOG("Got message", type, event);
|
||||||
|
|
@ -434,13 +668,40 @@ exports.message = function(type, event) {
|
||||||
if(!(type=="text" || type == "call")) return;
|
if(!(type=="text" || type == "call")) return;
|
||||||
if(type=="text" && event.id == "nav") return;
|
if(type=="text" && event.id == "nav") return;
|
||||||
if(event.handled) return;
|
if(event.handled) return;
|
||||||
|
if(event.messagesoverlayignore) return;
|
||||||
|
|
||||||
bpp = 4;
|
let free = process.memory().free;
|
||||||
if (process.memory().free < LOW_MEM)
|
bpp = settings.systemTheme ? 16 : 4;
|
||||||
|
|
||||||
|
let estimatedMemUse = bpp == 16 ? 4096 : (bpp == 4 ? 1536 : 768);
|
||||||
|
// reduce estimation if ovr already exists and uses memory;
|
||||||
|
if (ovr)
|
||||||
|
estimatedMemUse -= ovr.getBPP() == 16 ? 4096 : (ovr.getBPP() == 4 ? 1536 : 768);
|
||||||
|
|
||||||
|
if (process.memory().free - estimatedMemUse < settings.minfreemem * 1024) {
|
||||||
|
// we are going to be under our minfreemem setting if we proceed
|
||||||
bpp = 1;
|
bpp = 1;
|
||||||
|
if (ovr && ovr.getBPP() > 1){
|
||||||
|
// can reduce memory by going 1 bit
|
||||||
|
let saves = ovr.getBPP() == 16 ? 4096 - 768 : 768;
|
||||||
|
estimatedMemUse -= saves;
|
||||||
|
LOG("Go to 1 bit, saving", saves);
|
||||||
|
} else {
|
||||||
|
estimatedMemUse = 768;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (process.memory().free < MIN_FREE_MEM && eventQueue.length > 0){
|
|
||||||
let dropped = eventQueue.pop();
|
if (E.getSizeOf){
|
||||||
|
let e = E.getSizeOf(eventQueue);
|
||||||
|
estimatedMemUse += e;
|
||||||
|
LOG("EventQueue has", e, "blocks");
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG("Free ", free, "estimated use", estimatedMemUse, "for", bpp, "BPP");
|
||||||
|
|
||||||
|
while (process.memory().free - estimatedMemUse < settings.minfreemem * 1024 && eventQueue.length > 0){
|
||||||
|
const dropped = eventQueue.pop();
|
||||||
print("Dropped message because of memory constraints", dropped);
|
print("Dropped message because of memory constraints", dropped);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -448,19 +709,37 @@ exports.message = function(type, event) {
|
||||||
ovr = Graphics.createArrayBuffer(ovrw, ovrh, bpp, {
|
ovr = Graphics.createArrayBuffer(ovrw, ovrh, bpp, {
|
||||||
msb: true
|
msb: true
|
||||||
});
|
});
|
||||||
} else {
|
if(E.getSizeOf)
|
||||||
ovr.clear();
|
LOG("New overlay uses", E.getSizeOf(ovr), "blocks");
|
||||||
}
|
}
|
||||||
|
|
||||||
g = ovr;
|
ovr.reset();
|
||||||
|
|
||||||
if (bpp == 4)
|
if (bpp > 1){
|
||||||
ovr.theme = g.theme;
|
if (settings.systemTheme){
|
||||||
else
|
ovr.theme = g.theme;
|
||||||
ovr.theme = { fg:0, bg:1, fg2:1, bg2:0, fgH:1, bgH:0 };
|
} else {
|
||||||
|
ovr.theme = {
|
||||||
|
fg: g.theme.dark ? 15: 0,
|
||||||
|
bg: g.theme.dark ? 0: 15,
|
||||||
|
fg2: g.theme.dark ? 15: 0,
|
||||||
|
bg2: g.theme.dark ? 9 : 8,
|
||||||
|
fgH: g.theme.dark ? 15 : 0,
|
||||||
|
bgH: g.theme.dark ? 9: 8,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (g.theme.dark)
|
||||||
|
ovr.theme = { fg:1, bg:0, fg2:0, bg2:1, fgH:0, bgH:1 };
|
||||||
|
else
|
||||||
|
ovr.theme = { fg:0, bg:1, fg2:1, bg2:0, fgH:1, bgH:0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
main(event);
|
||||||
|
|
||||||
|
updateClearingTimeout();
|
||||||
|
|
||||||
main(ovr, event);
|
|
||||||
if (!isQuiet()) Bangle.setLCDPower(1);
|
|
||||||
event.handled = true;
|
event.handled = true;
|
||||||
g = _g;
|
g.flip();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "messagesoverlay",
|
"id": "messagesoverlay",
|
||||||
"name": "Messages Overlay",
|
"name": "Messages Overlay",
|
||||||
"version": "0.06",
|
"version": "0.07",
|
||||||
"description": "An overlay based implementation of a messages UI (display notifications from iOS and Gadgetbridge/Android)",
|
"description": "An overlay based implementation of a messages UI (display notifications from iOS and Gadgetbridge/Android)",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"type": "bootloader",
|
"type": "bootloader",
|
||||||
|
|
@ -11,7 +11,10 @@
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"messagesoverlay","url":"lib.js"},
|
{"name":"messagesoverlay","url":"lib.js"},
|
||||||
{"name":"messagesoverlay.0.boot.js","url":"boot.js"}
|
{"name":"messagesoverlay.0.boot.js","url":"boot.js"},
|
||||||
|
{"name":"messagesoverlay.settings.js","url":"settings.js"},
|
||||||
|
{"name":"messagesoverlay.default.json","url":"default.json"}
|
||||||
],
|
],
|
||||||
|
"data": [{"name":"bthrm.json"}],
|
||||||
"screenshots": [{"url":"screen_call.png"} ,{"url":"screen_message.png"} ]
|
"screenshots": [{"url":"screen_call.png"} ,{"url":"screen_message.png"} ]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
(function(back) {
|
||||||
|
function writeSettings(key, value) {
|
||||||
|
var s = require('Storage').readJSON(FILE, true) || {};
|
||||||
|
s[key] = value;
|
||||||
|
require('Storage').writeJSON(FILE, s);
|
||||||
|
readSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function readSettings(){
|
||||||
|
settings = Object.assign(
|
||||||
|
require('Storage').readJSON("messagesoverlay.default.json", true) || {},
|
||||||
|
require('Storage').readJSON(FILE, true) || {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var FILE="messagesoverlay.json";
|
||||||
|
var settings;
|
||||||
|
readSettings();
|
||||||
|
|
||||||
|
function buildMainMenu(){
|
||||||
|
var mainmenu = {
|
||||||
|
'' : { title: "Messages Overlay"},
|
||||||
|
'< Back': back,
|
||||||
|
'Border': {
|
||||||
|
value: settings.border,
|
||||||
|
min: 0,
|
||||||
|
max: Math.floor(g.getWidth()/2-50),
|
||||||
|
step: 1,
|
||||||
|
format: v=>v + "px",
|
||||||
|
onchange: v => {
|
||||||
|
writeSettings("border",v);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Autoclear after': {
|
||||||
|
value: settings.autoclear,
|
||||||
|
min: 0,
|
||||||
|
max: 3600,
|
||||||
|
step: 10,
|
||||||
|
format: v=>v>0?v+"s":"Off",
|
||||||
|
onchange: v => {
|
||||||
|
writeSettings("autoclear",v);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Theme': {
|
||||||
|
value: settings.systemTheme,
|
||||||
|
format: v=>v?"System":"low RAM",
|
||||||
|
onchange: v => {
|
||||||
|
writeSettings("systemTheme",v);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Min. free RAM': {
|
||||||
|
value: settings.minfreemem,
|
||||||
|
min: 0,
|
||||||
|
max: process.memory().total/1000,
|
||||||
|
step: 1,
|
||||||
|
format: v=>v + "k free",
|
||||||
|
onchange: v => {
|
||||||
|
writeSettings("minfreemem",v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mainmenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
E.showMenu(buildMainMenu());
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue