added app "Messages Light"
|
@ -0,0 +1,7 @@
|
|||
1.0: New App!
|
||||
1.1: fix app opening when a remove notification arrives
|
||||
1.2: message_light overrides require() by sending requests to "message" to a proxy library which overrides pushMessage
|
||||
settings now points to message settings
|
||||
implemented use of the "messageicons" library
|
||||
removed lib no longer used
|
||||
1.3: icon changed
|
|
@ -0,0 +1,11 @@
|
|||
# Messages app
|
||||
|
||||
This app handles the display of messages and message notifications.
|
||||
|
||||
It is a GUI replacement for the `messages` apps.
|
||||
|
||||
|
||||
## Creator
|
||||
|
||||
Rarder44
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEw4UA/4ACBIMQwhL/ABMBqoAEoALDioLFqgLDBQoABERIkEBZcFBY9QBYVe1QAB1YLGrSlC/YLGrYHCr4Lrr9drpLC1oLEAAN5rxKB/ILHEYV5EY4LIHYoLorRaBqoPCBYlfUoXrBYwGBrdeDIILIvXVBZFa1I+CBY/5BZIHBBwOq1ILGrXVvf//oLGq+trLLFBYVVvQxCBY9XJIQLCgILDHoVVoALHAAQLCgALHBQUAioKFqgLDEgwiDAH4AGA"))
|
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 3.2 KiB |
|
@ -0,0 +1,525 @@
|
|||
/* MESSAGES is a list of:
|
||||
{id:int,
|
||||
src,
|
||||
title,
|
||||
subject,
|
||||
body,
|
||||
sender,
|
||||
tel:string,
|
||||
new:true // not read yet
|
||||
}
|
||||
*/
|
||||
|
||||
let LOG=function(){
|
||||
//print.apply(null, arguments);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
let settings= (()=>{
|
||||
let tmp={};
|
||||
tmp.NewEventFileName="messages_light.NewEvent.json";
|
||||
|
||||
tmp.fontSmall = "6x8";
|
||||
tmp.fontMedium = g.getFonts().includes("Vector")?"Vector:16":"6x8:2";
|
||||
tmp.fontBig = g.getFonts().includes("12x20")?"12x20":"6x8:2";
|
||||
tmp.fontLarge = g.getFonts().includes("6x15")?"6x15:2":"6x8:4";
|
||||
|
||||
|
||||
tmp.colHeadBg = g.theme.dark ? "#141":"#4f4";
|
||||
tmp.colBg = g.theme.dark ? "#000":"#fff";
|
||||
tmp.colLock = g.theme.dark ? "#ff0000":"#ff0000";
|
||||
|
||||
tmp.quiet=((require('Storage').readJSON('setting.json', 1) || {}).quiet)
|
||||
|
||||
return tmp;
|
||||
})();
|
||||
let EventQueue=[]; //in posizione 0, c'è quello attualmente visualizzato
|
||||
let callInProgress=false;
|
||||
|
||||
|
||||
let main = function(){
|
||||
LOG("Main");
|
||||
//quando apro quest'app, do per scontato che c'è un messaggio da leggere posto in un file particolare ( NewMessage.json )
|
||||
let eventToShow = require('Storage').readJSON(settings.NewEventFileName, true);
|
||||
//require("Storage").erase(settings.NewEventFileName)
|
||||
if( eventToShow!==undefined)
|
||||
manageEvent(eventToShow);
|
||||
else
|
||||
load();
|
||||
};
|
||||
|
||||
|
||||
//TODO: RICORDARSI DI FARE IL DELETE
|
||||
var manageEvent = function(event) {
|
||||
|
||||
event.new=true;
|
||||
|
||||
|
||||
LOG("manageEvent");
|
||||
if( event.id=="call")
|
||||
{
|
||||
showCall(event);
|
||||
return;
|
||||
}
|
||||
switch(event.t)
|
||||
{
|
||||
case "add":
|
||||
EventQueue.unshift(event);
|
||||
|
||||
if(!callInProgress)
|
||||
showMessage(event);
|
||||
break;
|
||||
|
||||
case "modify":
|
||||
//cerco l'evento nella lista, se lo trovo, lo modifico, altrimenti lo pusho
|
||||
let find=false;
|
||||
EventQueue.forEach(element => {
|
||||
if(element.id == event.id)
|
||||
{
|
||||
find=true;
|
||||
Object.assign(element,event);
|
||||
}
|
||||
});
|
||||
if(!find) //se non l'ho trovato, lo aggiungo in fondo
|
||||
EventQueue.unshift(event);
|
||||
|
||||
if(!callInProgress)
|
||||
showMessage(event);
|
||||
break;
|
||||
|
||||
case "remove":
|
||||
|
||||
//se non c'è niente nella queue e non c'è una chiamata in corso
|
||||
if( EventQueue.length==0 && !callInProgress)
|
||||
next();
|
||||
|
||||
//se l'id è uguale a quello attualmente visualizzato ( e non siamo in chiamata )
|
||||
if(!callInProgress && EventQueue[0] !== undefined && EventQueue[0].id == event.id)
|
||||
next(); //passo al messaggio successivo ( per la rimozione ci penserà la next )
|
||||
|
||||
else{
|
||||
//altrimenti rimuovo tutti gli elementi con quell'id( creando un nuovo array )
|
||||
let newEventQueue=[];
|
||||
EventQueue.forEach(element => {
|
||||
if(element.id != event.id)
|
||||
newEventQueue.push(element);
|
||||
});
|
||||
EventQueue=newEventQueue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
break;
|
||||
case "musicstate":
|
||||
case "musicinfo":
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
let showMessage = function(msg){
|
||||
LOG("showMessage");
|
||||
LOG(msg);
|
||||
g.setBgColor(settings.colBg);
|
||||
|
||||
|
||||
if(typeof msg.CanScrollDown==="undefined")
|
||||
msg.CanScrollDown=false;
|
||||
if(typeof msg.CanScrollUp==="undefined")
|
||||
msg.CanScrollUp=false;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Normal text message display
|
||||
let title=msg.title, titleFont = settings.fontLarge, lines;
|
||||
if (title) {
|
||||
let w = g.getWidth()-48;
|
||||
if (g.setFont(titleFont).stringWidth(title) > w)
|
||||
titleFont = settings.fontMedium;
|
||||
if (g.setFont(titleFont).stringWidth(title) > w) {
|
||||
lines = g.wrapString(title, w);
|
||||
title = (lines.length>2) ? lines.slice(0,2).join("\n")+"..." : lines.join("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
let Layout = require("Layout");
|
||||
layout = new Layout({ type:"v", c: [
|
||||
{type:"h", fillx:1, bgCol:settings.colHeadBg, c: [
|
||||
{ type:"btn", src:require("messageicons").getImage(msg), col:require("messageicons").getColor(msg), pad: 3},
|
||||
{ type:"v", fillx:1, c: [
|
||||
{type:"txt", font:settings.fontSmall, label:msg.src||/*LANG*/"Message", bgCol:settings.colHeadBg, fillx:1, pad:2, halign:1 },
|
||||
title?{type:"txt", font:titleFont, label:title, bgCol:settings.colHeadBg, fillx:1, pad:2 }:{},
|
||||
]},
|
||||
]},
|
||||
{type:"v",fillx:1,filly:1,pad:2 ,halign:-1,c:[]},
|
||||
|
||||
|
||||
|
||||
|
||||
]});
|
||||
|
||||
|
||||
if (!settings.quiet && msg.new)
|
||||
{
|
||||
msg.new=false;
|
||||
Bangle.buzz();
|
||||
}
|
||||
|
||||
|
||||
g.clearRect(Bangle.appRect);
|
||||
layout.render();
|
||||
|
||||
PrintMessageStrings(msg);
|
||||
Bangle.setLCDPower(1);
|
||||
|
||||
DrawLock();
|
||||
|
||||
};
|
||||
let DrawLock=function()
|
||||
{
|
||||
let w=8,h=8;
|
||||
let x = g.getWidth()-w;
|
||||
let y = 0;
|
||||
if(Bangle.isLocked())
|
||||
g.setBgColor(settings.colLock);
|
||||
else
|
||||
g.setBgColor(settings.colHeadBg);
|
||||
g.clearRect(x,y,x+w,y+h);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
let showCall = function(msg)
|
||||
{
|
||||
LOG("showCall");
|
||||
LOG(msg);
|
||||
// se anche prima era una call PrevMessage==msg.id
|
||||
//non so perchè prima era cosi
|
||||
if( msg.t=="remove")
|
||||
{
|
||||
LOG("hide call screen");
|
||||
next(); //dont shift
|
||||
return;
|
||||
}
|
||||
|
||||
callInProgress=true;
|
||||
|
||||
|
||||
|
||||
//se è una chiamata ( o una nuova chiamata, diversa dalla precedente )
|
||||
//la visualizzo
|
||||
|
||||
var title=msg.title, titleFont = settings.fontLarge, lines;
|
||||
if (title) {
|
||||
var w = g.getWidth()-48;
|
||||
if (g.setFont(titleFont).stringWidth(title) > w)
|
||||
titleFont = settings.fontMedium;
|
||||
if (g.setFont(titleFont).stringWidth(title) > w) {
|
||||
lines = g.wrapString(title, w);
|
||||
title = (lines.length>2) ? lines.slice(0,2).join("\n")+"..." : lines.join("\n");
|
||||
}
|
||||
}
|
||||
let Layout = require("Layout");
|
||||
layout = new Layout({ type:"v", c: [
|
||||
{type:"h", fillx:1, bgCol:settings.colHeadBg, c: [
|
||||
{ type:"btn", src:require("messageicons").getImage(msg), col:require("messageicons").getColor(msg), pad: 3},
|
||||
{ type:"v", fillx:1, c: [
|
||||
{type:"txt", font:settings.fontSmall, label:msg.src||/*LANG*/"Message", bgCol:settings.colHeadBg, fillx:1, pad:2, halign:1 },
|
||||
title?{type:"txt", font:titleFont, label:title, bgCol:settings.colHeadBg, fillx:1, pad:2 }:{},
|
||||
]},
|
||||
]},
|
||||
{type:"txt", font:settings.fontMedium, label:msg.body, fillx:1,filly:1,pad:2 ,halign:0}
|
||||
]});
|
||||
|
||||
|
||||
StopBuzzCall();
|
||||
if ( !settings.quiet ) {
|
||||
if(msg.new)
|
||||
{
|
||||
msg.new=false;
|
||||
CallBuzzTimer = setInterval(function() {
|
||||
Bangle.buzz(500);
|
||||
}, 1000);
|
||||
|
||||
Bangle.buzz(500);
|
||||
}
|
||||
}
|
||||
g.clearRect(Bangle.appRect);
|
||||
layout.render();
|
||||
PrintMessageStrings(msg);
|
||||
Bangle.setLCDPower(1);
|
||||
DrawLock();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
let next=function(){
|
||||
LOG("next");
|
||||
StopBuzzCall();
|
||||
|
||||
|
||||
//se c'è una chiamata, non shifto
|
||||
if(!callInProgress)
|
||||
EventQueue.shift(); //passa al messaggio successivo, se presente - tolgo il primo
|
||||
|
||||
callInProgress=false;
|
||||
if( EventQueue.length == 0)
|
||||
{
|
||||
LOG("no element in queue - closing")
|
||||
setTimeout(_ => load());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
showMessage(EventQueue[0]);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
let showMapMessage=function(msg) {
|
||||
|
||||
g.clearRect(Bangle.appRect);
|
||||
PrintMessageStrings({body:"Not implemented!"});
|
||||
/*var m;
|
||||
var distance, street, target, eta;
|
||||
m=msg.title.match(/(.*) - (.*)/);
|
||||
if (m) {
|
||||
distance = m[1];
|
||||
street = m[2];
|
||||
} else street=msg.title;
|
||||
m=msg.body.match(/(.*) - (.*)/);
|
||||
if (m) {
|
||||
target = m[1];
|
||||
eta = m[2];
|
||||
} else target=msg.body;
|
||||
layout = new Layout({ type:"v", c: [
|
||||
{type:"txt", font:settings.fontMedium, label:target, bgCol:settings.colBg, fillx:1, pad:2 },
|
||||
{type:"h", bgCol:settings.colBg, fillx:1, c: [
|
||||
{type:"txt", font:"6x8", label:"Towards" },
|
||||
{type:"txt", font:settings.fontLarge, label:street }
|
||||
]},
|
||||
{type:"h",fillx:1, filly:1, c: [
|
||||
msg.img?{type:"img",src:atob(msg.img), scale:2}:{},
|
||||
{type:"v", fillx:1, c: [
|
||||
{type:"txt", font:settings.fontLarge, label:distance||"" }
|
||||
]},
|
||||
]},
|
||||
{type:"txt", font:"6x8:2", label:eta }
|
||||
]});
|
||||
g.clearRect(Bangle.appRect);
|
||||
layout.render();
|
||||
Bangle.setUI("updown",function() {
|
||||
// any input to mark as not new and return to menu
|
||||
msg.new = false;
|
||||
layout = undefined;
|
||||
checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1});
|
||||
});*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var CallBuzzTimer=null;
|
||||
let StopBuzzCall=function()
|
||||
{
|
||||
if (CallBuzzTimer){
|
||||
clearInterval(CallBuzzTimer);
|
||||
CallBuzzTimer=null;
|
||||
}
|
||||
}
|
||||
let DrawTriangleUp=function()
|
||||
{
|
||||
g.fillPoly([169,46,164,56,174,56]);
|
||||
}
|
||||
let DrawTriangleDown=function()
|
||||
{
|
||||
g.fillPoly([169,170,164,160,174,160]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
let ScrollUp=function()
|
||||
{
|
||||
msg= EventQueue[0];
|
||||
|
||||
if(typeof msg.FirstLine==="undefined")
|
||||
msg.FirstLine=0;
|
||||
if(typeof msg.CanScrollUp==="undefined")
|
||||
msg.CanScrollUp=false;
|
||||
|
||||
if(!msg.CanScrollUp) return;
|
||||
|
||||
msg.FirstLine = msg.FirstLine>0?msg.FirstLine-1:0;
|
||||
|
||||
PrintMessageStrings(msg);
|
||||
}
|
||||
let ScrollDown=function()
|
||||
{
|
||||
msg= EventQueue[0];
|
||||
if(typeof msg.FirstLine==="undefined")
|
||||
msg.FirstLine=0;
|
||||
if(typeof msg.CanScrollDown==="undefined")
|
||||
msg.CanScrollDown=false;
|
||||
|
||||
if(!msg.CanScrollDown) return;
|
||||
|
||||
msg.FirstLine = msg.FirstLine+1;
|
||||
PrintMessageStrings(msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
let PrintMessageStrings=function(msg)
|
||||
{
|
||||
let MyWrapString = function (str,maxWidth)
|
||||
{
|
||||
str=str.replace("\r\n","\n").replace("\r","\n");
|
||||
return g.wrapString(str,maxWidth);
|
||||
}
|
||||
|
||||
|
||||
if(typeof msg.FirstLine==="undefined") msg.FirstLine=0;
|
||||
|
||||
var bodyFont = typeof msg.bodyFont==="undefined"? settings.fontMedium : msg.bodyFont;
|
||||
var Padding=2;
|
||||
if(typeof msg.lines==="undefined")
|
||||
{
|
||||
g.setFont(bodyFont);
|
||||
msg.lines = MyWrapString(msg.body,g.getWidth()-(Padding*2))
|
||||
if ( msg.lines.length<=2)
|
||||
{
|
||||
bodyFont= g.getFonts().includes("Vector")?"Vector:20":"6x8:3";
|
||||
g.setFont(bodyFont);
|
||||
msg.lines = MyWrapString(msg.body,g.getWidth()-(Padding*2))
|
||||
msg.bodyFont = bodyFont;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//prendo le linee da stampare
|
||||
var NumLines=8;
|
||||
var linesToPrint = (msg.lines.length>NumLines) ? msg.lines.slice(msg.FirstLine,msg.FirstLine+NumLines):msg.lines;
|
||||
|
||||
|
||||
var yText=45;
|
||||
|
||||
//invalido l'area e disegno il testo
|
||||
g.setBgColor(settings.colBg);
|
||||
g.clearRect(0,yText,176,176);
|
||||
var xText=Padding;
|
||||
yText+=Padding;
|
||||
g.setFont(bodyFont);
|
||||
var HText=g.getFontHeight();
|
||||
|
||||
yText=((176-yText)/2)-(linesToPrint.length * HText / 2) + yText;
|
||||
|
||||
if( linesToPrint.length<=2)
|
||||
{
|
||||
g.setFontAlign(0,-1);
|
||||
xText = g.getWidth()/2;
|
||||
}
|
||||
else
|
||||
g.setFontAlign(-1,-1);
|
||||
|
||||
|
||||
linesToPrint.forEach((line, i)=>{
|
||||
g.drawString(line,xText,yText+HText*i);
|
||||
});
|
||||
|
||||
//disegno le freccie
|
||||
if(msg.FirstLine!=0)
|
||||
{
|
||||
msg.CanScrollUp=true;
|
||||
DrawTriangleUp();
|
||||
}
|
||||
else
|
||||
msg.CanScrollUp=false;
|
||||
|
||||
if(msg.FirstLine+linesToPrint.length < msg.lines.length)
|
||||
{
|
||||
msg.CanScrollDown=true;
|
||||
DrawTriangleDown();
|
||||
}
|
||||
else
|
||||
msg.CanScrollDown=false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
g.clear();
|
||||
|
||||
Bangle.on('lock', function(on) {
|
||||
DrawLock();
|
||||
});
|
||||
|
||||
//se c'è una chiamata in corso NON devo togliere niente dal next ( in q)
|
||||
setWatch(_=> next(), BTN1,{repeat: true});
|
||||
|
||||
|
||||
//il tap è il tocco con l'accellerometro!
|
||||
Bangle.on('tap', function(data) {
|
||||
if( data.double) //solo se in double
|
||||
{
|
||||
Bangle.setLocked(false);
|
||||
Bangle.setLCDPower(1);
|
||||
}
|
||||
});
|
||||
Bangle.on('touch', function(button, xy) {
|
||||
var height=176; //g.getHeight(); -> 176 B2
|
||||
height/=2;
|
||||
|
||||
if(xy.y<height)
|
||||
{
|
||||
ScrollUp();
|
||||
}
|
||||
else
|
||||
{
|
||||
ScrollDown();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
main();
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
//OLD CODE -> backup purpose
|
||||
|
||||
let messageBootManager=function(type,event){
|
||||
//se l'app non è aperta
|
||||
if ("undefined"==typeof manageEvent)
|
||||
{
|
||||
if(event.t=="remove") return; //l'app non è aperta, non c'è nessun messaggio da rimuovere dalla queue -> non lancio l'app
|
||||
|
||||
//la apro
|
||||
require("Storage").writeJSON("messages_light.NewEvent.json",{"event":event,"type":type});
|
||||
load("messages_light.app.js");
|
||||
}
|
||||
else
|
||||
{
|
||||
//altrimenti gli dico di gestire il messaggio
|
||||
manageEvent(type,event);
|
||||
}
|
||||
}
|
||||
Bangle.on("message", messageBootManager);
|
||||
Bangle.on("call", messageBootManager);*/
|
||||
|
||||
|
||||
|
||||
//override require to filter require("message")
|
||||
global.require_real=global.require;
|
||||
global.require = (_require => file => {
|
||||
if (file==="messages") file = "messagesProxy";
|
||||
//else if (file==="messages_REAL") file = "messages"; //backdoor to real message
|
||||
|
||||
return _require(file);
|
||||
})(require);
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
//gestisco il messaggio a modo mio
|
||||
exports.pushMessage = function(event) {
|
||||
|
||||
//TODO: musica non ancora gestita dall'app -> passo a message
|
||||
if( event.id=="music") return require_real("messages").pushMessage(event);
|
||||
|
||||
//se l'app non è aperta
|
||||
if ("undefined"==typeof manageEvent)
|
||||
{
|
||||
if(event.t=="remove") return; //l'app non è aperta, non c'è nessun messaggio da rimuovere dalla queue -> non lancio l'app
|
||||
|
||||
//la apro
|
||||
require_real("Storage").writeJSON("messages_light.NewEvent.json",event);
|
||||
load("messages_light.app.js");
|
||||
}
|
||||
else
|
||||
{
|
||||
//altrimenti gli dico di gestire il messaggio
|
||||
manageEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Call original message library
|
||||
exports.clearAll = function() { return require_real("messages").clearAll()}
|
||||
exports.getMessages = function() { return require_real("messages").getMessages()}
|
||||
exports.status = function() { return require_real("messages").status()}
|
||||
exports.buzz = function() { return require_real("messages").buzz(msgSrc)}
|
||||
exports.stopBuzz = function() { return require_real("messages").stopBuzz()}
|
|
@ -0,0 +1 @@
|
|||
eval(require("Storage").read("messages.settings.js"));
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"id": "messages_light",
|
||||
"name": "Messages Light",
|
||||
"version": "1.3",
|
||||
"description": "A light implementation of messages App (display notifications from iOS and Gadgetbridge/Android)",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
"tags": "tool,system",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"dependencies" : { "messageicons":"module","messages":"app" },
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"messages_light.app.js","url":"messages_light.app.js"},
|
||||
{"name":"messages_light.settings.js","url":"messages_light.settings.js"},
|
||||
{"name":"messages_light.img","url":"app-icon.js","evaluate":true},
|
||||
{"name":"messagesProxy","url":"messages_light.messagesProxy.js"},
|
||||
{"name":"messages_light.boot.js","url":"messages_light.boot.js"}
|
||||
],
|
||||
"data": [{"name":"messages_light.settings.json"},{"name":"messages_light.NewMessage.json"}],
|
||||
"screenshots": [{"url":"screenshot-notify.png"} ,{"url":"screenshot-long-text1.png"},{"url":"screenshot-long-text2.png"}, {"url":"screenshot-call.png"} ],
|
||||
"sortorder": -9
|
||||
}
|
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 3.1 KiB |