Merge pull request #155 from detached/call-notifications
Adds gbridge call notification and refactor widgetmaster
commit
9f3ecbc973
|
|
@ -2,4 +2,5 @@
|
||||||
0.02: Increase contrast (darker notification background, white text)
|
0.02: Increase contrast (darker notification background, white text)
|
||||||
0.03: Gadgetbridge widget now shows connection state
|
0.03: Gadgetbridge widget now shows connection state
|
||||||
0.04: Tweaks for variable size widget system
|
0.04: Tweaks for variable size widget system
|
||||||
0.05: Optimize animation, limit title length
|
0.05: Show incoming call notification
|
||||||
|
Optimize animation, limit title length
|
||||||
|
|
|
||||||
|
|
@ -1,126 +1,196 @@
|
||||||
(function() {
|
(() => {
|
||||||
var musicState = "stop";
|
|
||||||
var musicInfo = {"artist":"","album":"","track":""};
|
const state = {
|
||||||
var scrollPos = 0;
|
music: "stop",
|
||||||
function gb(j) {
|
|
||||||
Bluetooth.println(JSON.stringify(j));
|
musicInfo: {
|
||||||
|
artist: "",
|
||||||
|
album: "",
|
||||||
|
track: ""
|
||||||
|
},
|
||||||
|
|
||||||
|
scrollPos: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
function gbSend(message) {
|
||||||
|
Bluetooth.println(JSON.stringify(message));
|
||||||
}
|
}
|
||||||
function show(size,render) {
|
|
||||||
|
function showNotification(size, render) {
|
||||||
var oldMode = Bangle.getLCDMode();
|
var oldMode = Bangle.getLCDMode();
|
||||||
|
|
||||||
Bangle.setLCDMode("direct");
|
Bangle.setLCDMode("direct");
|
||||||
g.setClipRect(0,240,239,319);
|
g.setClipRect(0, 240, 239, 319);
|
||||||
g.setColor("#222222");
|
g.setColor("#222222");
|
||||||
g.fillRect(1,241,238,318);
|
g.fillRect(1, 241, 238, 318);
|
||||||
render(320-size);
|
|
||||||
|
render(320 - size);
|
||||||
|
|
||||||
g.setColor("#ffffff");
|
g.setColor("#ffffff");
|
||||||
g.fillRect(0,240,1,319);
|
g.fillRect(0, 240, 1, 319);
|
||||||
g.fillRect(238,240,239,319);
|
g.fillRect(238, 240, 239, 319);
|
||||||
g.fillRect(2,318,238,319);
|
g.fillRect(2, 318, 238, 319);
|
||||||
|
|
||||||
Bangle.setLCDPower(1); // light up
|
Bangle.setLCDPower(1); // light up
|
||||||
Bangle.setLCDMode(oldMode); // clears cliprect
|
Bangle.setLCDMode(oldMode); // clears cliprect
|
||||||
|
|
||||||
function anim() {
|
function anim() {
|
||||||
scrollPos-=2;
|
state.scrollPos -= 2;
|
||||||
if (scrollPos<-size) scrollPos=-size;
|
if (state.scrollPos < -size) {
|
||||||
Bangle.setLCDOffset(scrollPos);
|
state.scrollPos = -size;
|
||||||
if (scrollPos>-size) setTimeout(anim,15);
|
|
||||||
}
|
}
|
||||||
anim();
|
Bangle.setLCDOffset(state.scrollPos);
|
||||||
}
|
if (state.scrollPos > -size) setTimeout(anim, 15);
|
||||||
function hide() {
|
|
||||||
function anim() {
|
|
||||||
scrollPos+=4;
|
|
||||||
if (scrollPos>0) scrollPos=0;
|
|
||||||
Bangle.setLCDOffset(scrollPos);
|
|
||||||
if (scrollPos<0) setTimeout(anim,10);
|
|
||||||
}
|
}
|
||||||
anim();
|
anim();
|
||||||
}
|
}
|
||||||
|
|
||||||
Bangle.on('touch',function() {
|
function hideNotification() {
|
||||||
if (scrollPos) hide();
|
function anim() {
|
||||||
});
|
state.scrollPos += 4;
|
||||||
Bangle.on('swipe',function(dir) {
|
if (state.scrollPos > 0) state.scrollPos = 0;
|
||||||
if (musicState=="play") {
|
Bangle.setLCDOffset(state.scrollPos);
|
||||||
gb({t:"music",n:dir>0?"next":"previous"});
|
if (state.scrollPos < 0) setTimeout(anim, 10);
|
||||||
|
}
|
||||||
|
anim();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
gb({t:"status",bat:E.getBattery()});
|
|
||||||
|
|
||||||
global.GB = function(j) {
|
function handleNotificationEvent(event) {
|
||||||
switch (j.t) {
|
|
||||||
case "notify":
|
// split text up at word boundaries
|
||||||
show(80,function(y) {
|
var txt = event.body.split("\n");
|
||||||
// TODO: icon based on src?
|
|
||||||
var x = 120;
|
|
||||||
g.setFontAlign(0,0);
|
|
||||||
g.setFont("6x8",1);
|
|
||||||
g.setColor("#40d040");
|
|
||||||
g.drawString(j.src,x,y+7);
|
|
||||||
g.setColor("#ffffff");
|
|
||||||
g.setFont("6x8",2);
|
|
||||||
if (j.title === undefined) g.drawString(j.title,x,y+25);
|
|
||||||
else g.drawString(j.title.slice(0,17),x,y+25);
|
|
||||||
g.setFont("6x8",1);
|
|
||||||
g.setColor("#ffffff");
|
|
||||||
// split text up a word boundaries
|
|
||||||
var txt = j.body.split("\n");
|
|
||||||
var MAXCHARS = 38;
|
var MAXCHARS = 38;
|
||||||
for (var i=0;i<txt.length;i++) {
|
for (var i = 0; i < txt.length; i++) {
|
||||||
txt[i] = txt[i].trim();
|
txt[i] = txt[i].trim();
|
||||||
var l = txt[i];
|
var l = txt[i];
|
||||||
if (l.length>MAXCHARS) {
|
if (l.length > MAXCHARS) {
|
||||||
var p = MAXCHARS;
|
var p = MAXCHARS;
|
||||||
while (p>MAXCHARS-8 && !" \t-_".includes(l[p]))
|
while (p > MAXCHARS - 8 && !" \t-_".includes(l[p]))
|
||||||
p--;
|
p--;
|
||||||
if (p==MAXCHARS-8) p=MAXCHARS;
|
if (p == MAXCHARS - 8) p = MAXCHARS;
|
||||||
txt[i] = l.substr(0,p);
|
txt[i] = l.substr(0, p);
|
||||||
txt.splice(i+1,0,l.substr(p));
|
txt.splice(i + 1, 0, l.substr(p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.setFontAlign(-1,-1);
|
|
||||||
g.drawString(txt.join("\n"),10,y+40);
|
showNotification(80, (y) => {
|
||||||
Bangle.buzz();
|
|
||||||
|
// TODO: icon based on src?
|
||||||
|
var x = 120;
|
||||||
|
g.setFontAlign(0, 0);
|
||||||
|
g.setFont("6x8", 1);
|
||||||
|
g.setColor("#40d040");
|
||||||
|
g.drawString(event.src, x, y + 7);
|
||||||
|
|
||||||
|
g.setColor("#ffffff");
|
||||||
|
g.setFont("6x8", 2);
|
||||||
|
if (event.title)
|
||||||
|
g.drawString(event.title.slice(0,17), x, y + 25);
|
||||||
|
|
||||||
|
g.setFont("6x8", 1);
|
||||||
|
g.setColor("#ffffff");
|
||||||
|
g.setFontAlign(-1, -1);
|
||||||
|
g.drawString(txt.join("\n"), 10, y + 40);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Bangle.buzz();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMusicStateUpdate(event) {
|
||||||
|
state.music = event.state
|
||||||
|
|
||||||
|
if (state.music == "play") {
|
||||||
|
showNotification(40, (y) => {
|
||||||
|
g.setColor("#ffffff");
|
||||||
|
g.drawImage(require("heatshrink").decompress(atob("jEYwILI/EAv/8gP/ARcMgOAASN8h+A/kfwP8n4CD/E/gHgjg/HA=")), 8, y + 8);
|
||||||
|
|
||||||
|
g.setFontAlign(-1, -1);
|
||||||
|
var x = 40;
|
||||||
|
g.setFont("4x6", 2);
|
||||||
|
g.setColor("#ffffff");
|
||||||
|
g.drawString(state.musicInfo.artist, x, y + 8);
|
||||||
|
|
||||||
|
g.setFont("6x8", 1);
|
||||||
|
g.setColor("#ffffff");
|
||||||
|
g.drawString(state.musicInfo.track, x, y + 22);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.music == "pause") {
|
||||||
|
hideNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCallEvent(event) {
|
||||||
|
|
||||||
|
if (event.cmd == "accept") {
|
||||||
|
showNotification(40, (y) => {
|
||||||
|
g.setColor("#ffffff");
|
||||||
|
g.drawImage(require("heatshrink").decompress(atob("jEYwIMJj4CCwACJh4CCCIMOAQMGAQMHAQMDAQMBCIMB4PwgHz/EAn4CBj4CBg4CBgACCAAw=")), 8, y + 8);
|
||||||
|
|
||||||
|
g.setFontAlign(-1, -1);
|
||||||
|
var x = 40;
|
||||||
|
g.setFont("4x6", 2);
|
||||||
|
g.setColor("#ffffff");
|
||||||
|
g.drawString(event.name, x, y + 8);
|
||||||
|
|
||||||
|
g.setFont("6x8", 1);
|
||||||
|
g.setColor("#ffffff");
|
||||||
|
g.drawString(event.number, x, y + 22);
|
||||||
|
});
|
||||||
|
|
||||||
|
Bangle.buzz();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global.GB = (event) => {
|
||||||
|
switch (event.t) {
|
||||||
|
case "notify":
|
||||||
|
handleNotificationEvent(event);
|
||||||
break;
|
break;
|
||||||
case "musicinfo":
|
case "musicinfo":
|
||||||
musicInfo = j;
|
state.musicInfo = event;
|
||||||
break;
|
break;
|
||||||
case "musicstate":
|
case "musicstate":
|
||||||
musicState = j.state;
|
handleMusicStateUpdate(event);
|
||||||
if (musicState=="play")
|
break;
|
||||||
show(40,function(y) {
|
case "call":
|
||||||
g.setColor("#ffffff");
|
handleCallEvent(event);
|
||||||
g.drawImage(require("heatshrink").decompress(atob("jEYwILI/EAv/8gP/ARcMgOAASN8h+A/kfwP8n4CD/E/gHgjg/HA=")),8,y+8);
|
|
||||||
g.setFontAlign(-1,-1);
|
|
||||||
g.setFont("6x8",1);
|
|
||||||
var x = 40;
|
|
||||||
g.setFont("4x6",2);
|
|
||||||
g.setColor("#ffffff");
|
|
||||||
g.drawString(musicInfo.artist,x,y+8);
|
|
||||||
g.setFont("6x8",1);
|
|
||||||
g.setColor("#ffffff");
|
|
||||||
g.drawString(musicInfo.track,x,y+22);
|
|
||||||
});
|
|
||||||
if (musicState=="pause")
|
|
||||||
hide();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function draw() {
|
// Touch control
|
||||||
|
Bangle.on("touch", () => {
|
||||||
|
if (state.scrollPos) {
|
||||||
|
hideNotification();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Bangle.on("swipe", (dir) => {
|
||||||
|
if (state.music == "play") {
|
||||||
|
const command = dir > 0 ? "next" : "previous"
|
||||||
|
gbSend({ t: "music", n: command });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function draw() {
|
||||||
g.setColor(-1);
|
g.setColor(-1);
|
||||||
if (NRF.getSecurityStatus().connected)
|
if (NRF.getSecurityStatus().connected)
|
||||||
g.drawImage(require("heatshrink").decompress(atob("i0WwgHExAABCIwJCBYwJEBYkIBQ2ACgvzCwoECx/z/AKDD4WD+YLBEIYKCx//+cvnAKCBwU/mc4/8/HYv//Ev+Y4EEAePn43DBQkzn4rCEIoABBIwKHO4cjmczK42I6mqlqEEBQeIBQaDED4IgDUhi6KaBbmIA==")),this.x+1,this.y+1);
|
g.drawImage(require("heatshrink").decompress(atob("i0WwgHExAABCIwJCBYwJEBYkIBQ2ACgvzCwoECx/z/AKDD4WD+YLBEIYKCx//+cvnAKCBwU/mc4/8/HYv//Ev+Y4EEAePn43DBQkzn4rCEIoABBIwKHO4cjmczK42I6mqlqEEBQeIBQaDED4IgDUhi6KaBbmIA==")), this.x + 1, this.y + 1);
|
||||||
else
|
else
|
||||||
g.drawImage(require("heatshrink").decompress(atob("i0WwQFC1WgAgYFDAgIFClQFCwEK1W/AoIPB1f+CAMq1f7/WqwQPB/fq1Gq1/+/4dC/2/CAIaB/YbBAAO///qAoX/B4QbBDQQ7BDQQrBAAWoIIIACIIIVC0ECB4cACAZiBAoRtCAoIDBA")),this.x+1,this.y+1);
|
g.drawImage(require("heatshrink").decompress(atob("i0WwQFC1WgAgYFDAgIFClQFCwEK1W/AoIPB1f+CAMq1f7/WqwQPB/fq1Gq1/+/4dC/2/CAIaB/YbBAAO///qAoX/B4QbBDQQ7BDQQrBAAWoIIIACIIIVC0ECB4cACAZiBAoRtCAoIDBA")), this.x + 1, this.y + 1);
|
||||||
}
|
}
|
||||||
function changed() {
|
|
||||||
|
function changedConnectionState() {
|
||||||
WIDGETS["gbridgew"].draw();
|
WIDGETS["gbridgew"].draw();
|
||||||
g.flip();// turns screen on
|
g.flip(); // turns screen on
|
||||||
}
|
}
|
||||||
NRF.on('connected',changed);
|
|
||||||
NRF.on('disconnected',changed);
|
|
||||||
|
|
||||||
WIDGETS["gbridgew"]={area:"tl",width:24,draw:draw};
|
NRF.on("connected", changedConnectionState);
|
||||||
|
NRF.on("disconnected", changedConnectionState);
|
||||||
|
|
||||||
|
WIDGETS["gbridgew"] = { area: "tl", width: 24, draw: draw };
|
||||||
|
|
||||||
|
gbSend({ t: "status", bat: E.getBattery() });
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue