tweak swipe animations, use UI swipe mode for left right swipes to try to make it feel snappier, fix scrolling issues

master
Bryan 2024-08-10 22:34:23 -06:00
parent df67d082fa
commit 136c73a85f
4 changed files with 246 additions and 181 deletions

View File

@ -1,5 +1,3 @@
let options = { let options = {
srcFont: "6x8", srcFont: "6x8",
titleFont: "12x20", titleFont: "12x20",
@ -32,8 +30,8 @@ const centerString = (str, x, y, w) => {
HeaderBox = function(msg, messageRect) { HeaderBox = function(msg, messageRect) {
this.icon = require("messageicons").getImage(msg); this.icon = require("messageicons").getImage(msg);
this.color = require("messageicons").getColor(msg, {default:g.theme.fg2}); this.color = require("messageicons").getColor(msg, {default:g.theme.fg2});
this.iconW = 48; this.iconSize = 48;
this.titleW = messageRect.w - this.iconW; this.titleW = messageRect.w - this.iconSize;
if (!msg.body) this.titleLines = ""; if (!msg.body) this.titleLines = "";
else { else {
this.titleLines = (() => { this.titleLines = (() => {
@ -50,14 +48,14 @@ HeaderBox = function(msg, messageRect) {
this.titleX = 0; this.titleX = 0;
this.titleY = 0; this.titleY = 0;
this.srcLineH = g.setFont(options.srcFont).getFontHeight(); this.srcLineH = g.setFont(options.srcFont).getFontHeight();
this.srcLines = g.wrapString(msg.src, this.iconW); this.srcLines = g.wrapString(msg.src, this.iconSize);
this.srcH = this.srcLineH * this.srcLines.length; this.srcH = this.srcLineH * this.srcLines.length;
this.srcX = this.x2 - this.iconW; this.srcX = this.x2 - this.iconSize;
this.srcY = 0; this.srcY = 0;
this.im = g.imageMetrics(this.icon); this.im = g.imageMetrics(this.icon);
this.imgX = this.titleW + ((this.iconW - this.im.width) / 2); this.imgX = this.titleW + ((this.iconSize - this.im.width) / 2);
this.minH = Math.max(this.titleLineH, this.srcH + this.im.height) + options.padding; this.minH = Math.max(this.titleLineH, this.srcH + this.im.height) + options.padding;
this.maxH = Math.max(this.titleLineH * this.titleLines.length, this.iconW) + options.padding; this.maxH = Math.max(this.titleLineH * this.titleLines.length, this.iconSize) + options.padding;
this.h = this.maxH; this.h = this.maxH;
this.new = msg.new ?? false; this.new = msg.new ?? false;
}; // HeaderBox }; // HeaderBox
@ -77,7 +75,7 @@ HeaderBox.prototype.draw = function(messageRect) {
g.setColor(options.headerFgColor); g.setColor(options.headerFgColor);
g.setFont(options.titleFont); g.setFont(options.titleFont);
if (this.h > this.minH) { // multi-line title if (this.h > this.minH) { // multi-line title
let titleY = y + 3; let titleY = Math.floor(((this.h - options.padding - (this.titleLineH * this.titleLines.length)) / 2) + y);
if (this.titleLines) { if (this.titleLines) {
for (let line of this.titleLines) { for (let line of this.titleLines) {
centerString(line, x, titleY, this.titleW); centerString(line, x, titleY, this.titleW);
@ -92,7 +90,7 @@ HeaderBox.prototype.draw = function(messageRect) {
if (this.h == this.maxH) { if (this.h == this.maxH) {
let srcY = y+4; let srcY = y+4;
for (let line of this.srcLines) { for (let line of this.srcLines) {
centerString(line, x2 - this.iconW, srcY, this.iconW); centerString(line, x2 - this.iconSize, srcY, this.iconSize);
srcY += this.srcLineH; srcY += this.srcLineH;
} }
} }
@ -107,8 +105,7 @@ const TextBox = function(msg, messageRect) {
if (msg.subject) { // If there's a subject, add it to the top if (msg.subject) { // If there's a subject, add it to the top
lines.splice(0, 0, msg.subject); lines.splice(0, 0, msg.subject);
} }
this.initScrollY = 0; this.scrollY = 0;
this.scrollY = this.initScrollY;
this.minY = messageRect.y2 - (this.lineH * (this.lines.length + 3)); this.minY = messageRect.y2 - (this.lineH * (this.lines.length + 3));
if (this.minY > 0) this.minY = 0; if (this.minY > 0) this.minY = 0;
}; // TextBox }; // TextBox
@ -144,7 +141,7 @@ MessageBox = function(msg, yOffset) {
this.headerBox = new HeaderBox(msg, this.rect); this.headerBox = new HeaderBox(msg, this.rect);
this.textBox = new TextBox(msg, this.rect); this.textBox = new TextBox(msg, this.rect);
let messageH = this.textBox.lines.length * this.textBox.lineH; let messageH = this.textBox.lines.length * this.textBox.lineH;
let boxH = this.rect.h - this.headerBox.maxH; let boxH = this.rect.h - this.headerBox.maxH - options.fh;
if ( messageH <= boxH) this.oneScreen = true; if ( messageH <= boxH) this.oneScreen = true;
else this.oneScreen = false; else this.oneScreen = false;
this.top = true; this.top = true;
@ -155,6 +152,7 @@ MessageBox = function(msg, yOffset) {
this.bottom = false; this.bottom = false;
this.textBox.initScrollY = 0; this.textBox.initScrollY = 0;
} }
this.textBox.scrollY = this.textBox.initScrollY;
this.sbH = this.rect.h / messageH * this.rect.h; // scrollbar height this.sbH = this.rect.h / messageH * this.rect.h; // scrollbar height
this.sbRatio = (this.rect.h - this.sbH) / Math.abs(this.textBox.minY); // scrollbar ratio this.sbRatio = (this.rect.h - this.sbH) / Math.abs(this.textBox.minY); // scrollbar ratio
}; // MessageBox }; // MessageBox
@ -201,9 +199,10 @@ MessageBox.prototype.drawScrollbar = function() {
}; };
MessageBox.prototype.scroll = function(dy) { MessageBox.prototype.scroll = function(dy) {
if ((dy > 0 && this.top) || (dy < 0 && this.bottom)) { if (this.oneScreen) return;
return; // if ((dy > 0 && this.top) || (dy < 0 && this.bottom)) {
} // return;
// }
if (this.headerBox.h > this.headerBox.minH && dy < 0) { if (this.headerBox.h > this.headerBox.minH && dy < 0) {
this.headerBox.h += dy; this.headerBox.h += dy;
if (this.headerBox.h < this.headerBox.minH) this.headerBox.h = this.headerBox.minH; if (this.headerBox.h < this.headerBox.minH) this.headerBox.h = this.headerBox.minH;
@ -228,44 +227,7 @@ MessageBox.prototype.scroll = function(dy) {
this.draw(); this.draw();
}; };
// SwipeBox = function(msg, screenRect) {
// this.msg = msg;
// this.screenRect = screenRect;
//
// console.log("screenRect = ", screenRect);
// console.log("this.screenRect = ", this.screenRect);
// this.headerBox = new HeaderBox(msg, screenRect);
// //this.bodyRect = {x: screenRect.x, y: screenRect.y + headerBox.h, x2: screenRect.x2, y2: screenRect.y2};
//
// };
//
// SwipeBox.prototype.draw = function(xOffset) {
// const x = this.screenRect.x, y = this.screenRect.y + this.headerBox.h, x2 = this.screenRect.x2, y2 = this.screenRect.y2;
// //const w = x2 - x + 1;
// const mx = (x + x2) / 2;
// //const yOff = 127 - this.headerBox.h;
// this.headerBox.draw(this.screenRect);
// g.reset();
//
// // g.setFont("6x15:2").setFontAlign(0,-1);
// // g.drawString(this.msg.body, mx, y);
// g.setColor(0,1,0);
// g.drawImage(incomingImg, mx-25, y+20);
//
// const drawArrows = function(xOffset) {
// g.setColor(1 ,0.25, 0.25);
// g.drawImage(leftImg, x+2, y2-50);
// g.setColor(0, 1, 0);
// g.drawImage(rightImg, x2-50, y2-50);
//
// }
//
// drawArrows(xOffset);
// };
module.exports.HeaderBox = HeaderBox; module.exports.HeaderBox = HeaderBox;
module.exports.MessageBox = MessageBox; module.exports.MessageBox = MessageBox;
//module.exports.SwipeBox = SwipeBox;
module.exports.setOptions = setOptions; module.exports.setOptions = setOptions;
module.exports.setClipRect = setClipRect; module.exports.setClipRect = setClipRect;

View File

@ -1,9 +1,9 @@
//{ //{
//let settings = require('Storage').readJSON("messages.settings.json", true) || {}; // let settings = require('Storage').readJSON("messages.settings.json", true) || {};
//const settings = () => require("messagegui").settings(); // const settings = () => require("messagegui").settings();
const fontTiny = "6x8"; // fixed size, don't use this for important things // let fontTiny = "6x8"; // fixed size, don't use this for important things
let fontNormal; // let fontNormal;
// setFont() is also called after we close the settings screen // setFont() is also called after we close the settings screen
// const setFont = function() { // const setFont = function() {
// const fontSize = settings().fontSize; // const fontSize = settings().fontSize;
@ -45,13 +45,15 @@ const setListener = function(event, callback) {
const _cleanup = function() { const _cleanup = function() {
for (let e in events) if (e) Bangle.removeListener(e, events[e]); for (let e in events) if (e) Bangle.removeListener(e, events[e]);
for (let t in timeouts) if (timeouts[t]) clearTimeout(timeouts[t]); console.log(timeouts);
for (let t in timeouts) clearTimeout(timeouts[t]);
require("messages").stopBuzz(); require("messages").stopBuzz();
require("widget_utils").show(); require("widget_utils").show();
Bangle.drawWidgets();
}; };
const clearTimeouts = function() { const clearTimeouts = function() {
for (let t in timeouts) if (timeouts[t]) clearTimeout(timeouts[t]); for (let t in timeouts) clearTimeout(timeouts[t]);
}; };
const showNoMessages = function() { const showNoMessages = function() {
@ -120,31 +122,44 @@ const showCall = function(call) {
headerBox.draw(Bangle.appRect); headerBox.draw(Bangle.appRect);
g.reset(); g.reset();
const drawLeftArrow = function(imgX) { const drawAcceptArrow = function(xOffset) {
imgX = imgX ?? x+2; xOffset = xOffset??0;
g.setColor(1 ,0.25, 0.25); imgX = x + 2 + xOffset;
g.drawImage(leftImg, imgX, y2-50);
};
const drawRightArrow = function(imgX) {
imgX = imgX ?? x2-50;
g.setColor(0, 1, 0); g.setColor(0, 1, 0);
g.drawImage(rightImg, imgX, y2-50); g.drawImage(rightImg, imgX, y2-50);
//if (xOffset > 0) g.fillRect(imgX+3, y2-43, x, y2-9);
}; };
const drawRejectArrow = function(xOffset) {
xOffset = xOffset??0;
let imgX = x2 - 50 - xOffset;
g.setColor(1, 0.25, 0.25);
g.drawImage(leftImg, imgX, y2-50);
//if (xOffset > 0) g.fillRect(imgX+45, y2-43, x2, y2-9);
};
if (cmd === "end") { if (cmd === "end") {
console.log("end");
if (timeouts.timer) clearTimeout(timeouts.timer); if (timeouts.timer) clearTimeout(timeouts.timer);
let elapsedString = Bangle.elapsedString;
delete Bangle.elapsedString;
g.setColor(g.theme.fg).setFont("6x15:2").setFontAlign(0, -1); g.setColor(g.theme.fg).setFont("6x15:2").setFontAlign(0, -1);
g.drawString("Call Ended", mx, y+25); g.setFont("Vector:25").setFontAlign(0, -1).drawString(elapsedString, mx, y+25);
endTimeout = setTimeout(() => g.clear(), 3000); g.drawString("Call Ended", mx, y);
const done = new Promise((resolve, _reject) => {
setTimeout(() => {resolve();}, 5000);
});
done.then(goBack);
} }
if (cmd === "incoming") { if (cmd === "incoming") {
drawLeftArrow(); drawRejectArrow();
drawRightArrow(); drawAcceptArrow();
g.setColor(0,1,0); g.setColor(0,1,0);
g.drawImage(ringingImg, mx-25, y+15); g.drawImage(ringingImg, mx-25, y+15);
} }
if (cmd === "start" || cmd === "outgoing") { if (cmd === "start" || cmd === "outgoing") {
drawLeftArrow(x2 - 52); drawRejectArrow();
startTime = parseInt(Date.now()/1000); startTime = parseInt(Date.now()/1000);
g.setColor(g.theme.fg); g.setColor(g.theme.fg);
g.drawImage(cmd === "start" ? incomingImg : outgoingImg, x+10, y+20); g.drawImage(cmd === "start" ? incomingImg : outgoingImg, x+10, y+20);
@ -154,23 +169,62 @@ const showCall = function(call) {
const h = ("0" + Math.floor((elapsed/3600)%60)).slice(-2); const h = ("0" + Math.floor((elapsed/3600)%60)).slice(-2);
const m = ("0" + Math.floor((elapsed/60)%60)).slice(-2); const m = ("0" + Math.floor((elapsed/60)%60)).slice(-2);
const s = ("0" + Math.floor(elapsed%60)).slice(-2); const s = ("0" + Math.floor(elapsed%60)).slice(-2);
g.setFont("Vector:25").setFontAlign(0, -1).drawString(`${h}:${m}:${s}`, mx + 15, y+25); Bangle.elapsedString = `${h}:${m}:${s}`;
timeouts.timer = setTimeout(timer, 1000); g.setFont("Vector:25").setFontAlign(0, -1).drawString(Bangle.elapsedString, mx + 15, y+25);
timeouts["timer"] = setTimeout(timer, 1000);
}; };
timer(); timer();
} }
const handler = function(dir) { const handler = function(dir) {
if (cmd === "end") return; if (cmd === "end") return;
if (dir < 0) return Bangle.messageResponse(msg, false); if (dir < 0) leftHandler(dir);
else if (dir > 0 && cmd === "incoming") return Bangle.messageResponse(msg, true); else if (dir > 0 && cmd === "incoming") rightHandler();
};
const leftHandler = function(dir) {
let xOff = 0;
const animate = new Promise((resolve, _reject) => {
const swipeAnimation = () => {
xOff += 30;
g.clearRect(x, y2-50, x2, y2);
drawRejectArrow(xOff);
if (xOff > 160) return resolve();
else setTimeout(swipeAnimation, 30);
}
swipeAnimation();
});
animate.then(() => {
if (timeouts.timer) clearTimeout(timeouts["timer"]);
Bangle.messageResponse(msg, false);
goBack();
});
};
const rightHandler = function(dir) {
let xOff = 0;
const animate = new Promise((resolve, _reject) => {
const swipeAnimation = () => {
xOff += 30;
g.clearRect(x, y2-50, x2, y2);
drawAcceptArrow(xOff);
if (xOff > 160) return resolve();
else setTimeout(swipeAnimation, 30);
}
swipeAnimation();
});
animate.then(() => {
if (timeouts.timer) clearTimeout(timeouts["timer"]);
Bangle.messageResponse(msg, true);
goBack();
});
}; };
Bangle.setUI({ Bangle.setUI({
mode: "custom", mode: "custom",
touch: () => {if (buzzing) return require("messages".stopBuzz())}, touch: () => {if (buzzing) return require("messages").stopBuzz()},
swipe: handler, swipe: handler,
btn: _e => goBack(), btn: _e => goBack,
remove: cleanup remove: cleanup
}); });
}; };
@ -179,8 +233,8 @@ const showText = function(messageNum) {
g.reset().clear(); g.reset().clear();
if (!Bangle.MESSAGES.length) return goBack(); // no messages if (!Bangle.MESSAGES.length) return goBack(); // no messages
setBusy(); // busy until everything is set up setBusy(); // busy until everything is set up
let showAll = false; //let showAll = false;
if (messageNum === undefined) {messageNum = 0; showAll = true;} if (messageNum === undefined) {messageNum = 0;} //showAll = true;}
else if (messageNum >= Bangle.MESSAGES.length - 1) messageNum = Bangle.MESSAGES.length - 1; else if (messageNum >= Bangle.MESSAGES.length - 1) messageNum = Bangle.MESSAGES.length - 1;
Bangle.setUI(); // make sure to clear setUI from anything previous Bangle.setUI(); // make sure to clear setUI from anything previous
let switching = false; let switching = false;
@ -188,19 +242,19 @@ const showText = function(messageNum) {
require("messagebox").setOptions({fh: 20}); require("messagebox").setOptions({fh: 20});
const step = 42; const step = 42;
const delay = 30; const delay = 30;
const swipeThreshold = 20; //const swipeThreshold = 20;
let mode = "scroll"; // one of "scroll", "next", "prev" (switch to next/prev message), "swipe" (swipe to delete or archive) let mode = "scroll"; // one of "scroll", "next", "prev" (switch to next/prev message), "swipe" (swipe to delete or archive)
msgIdx = messageNum; // global message index msgIdx = messageNum; // global message index
// TODO we might have to append array of (m.show && !m.new) to array of m.new so that all new messages are at the beginning of list // TODO we might have to append array of (m.show && !m.new) to array of m.new so that all new messages are at the beginning of list
let messageList = showAll ? Bangle.MESSAGES : Bangle.MESSAGES.filter(m => m.new || m.show); //let messageList = showAll ? Bangle.MESSAGES : Bangle.MESSAGES.filter(m => m.new || m.show || !m.handled);
if (!messageList.length) return goBack(); //if (!messageList.length) return goBack();
// Bangle.setLocked(false); // TODO make as option // Bangle.setLocked(false); // TODO make as option
// Bangle.setLCDPower(true); // TODO make as option // Bangle.setLCDPower(true); // TODO make as option
let msgBoxes = []; let msgBoxes = [];
let i = 0; let i = 0;
for (let msg of messageList) { for (let msg of Bangle.MESSAGES) {
msgBoxes[i] = new MessageBox(msg); msgBoxes[i] = new MessageBox(msg);
if (i === messageNum - 1) msgBoxes[i].yOffset = MessageBox.prototype.prevOffset; if (i === messageNum - 1) msgBoxes[i].yOffset = MessageBox.prototype.prevOffset;
else if (i === messageNum) { else if (i === messageNum) {
@ -214,30 +268,24 @@ const showText = function(messageNum) {
const drawFooter = function() { const drawFooter = function() {
let fh = 20; // footer height let fh = 20; // footer height
// left hint: swipe from left for main menu // left hint: swipe from left for main menu
g.reset().setBgColor(g.theme.bg2).clearRect(Bangle.appRect.x, Bangle.appRect.y2-fh, Bangle.appRect.x2, Bangle.appRect.y2) g.reset().setBgColor(g.theme.bg).clearRect(Bangle.appRect.x, Bangle.appRect.y2-fh, Bangle.appRect.x2, Bangle.appRect.y2)
.setColor(g.theme.bgH).drawLine(Bangle.appRect.x, Bangle.appRect.y2-fh, Bangle.appRect.x2, Bangle.appRect.y2-fh)
.setFont("6x15") // TODO make as option .setFont("6x15") // TODO make as option
.setFontAlign(-1, 1) // bottom left .setFontAlign(-1, 1).setColor(0, 1, 0) //bottom left
.drawString( .drawString(">>", Bangle.appRect.x + 1, Bangle.appRect.y2);
//"\0"+atob("CAiBAEgkEgkSJEgA"), // >>
">>",
Bangle.appRect.x + 1, Bangle.appRect.y2
);
// center message count+hints: swipe up/down for next/prev message // center message count+hints: swipe up/down for next/prev message
const footer = ` ${messageNum + 1}/${msgBoxes.length} `; const footer = ` ${messageNum + 1}/${msgBoxes.length} `;
const fw = g.stringWidth(footer); const fw = g.stringWidth(footer);
g.setFontAlign(0, 1); // bottom center g.setFontAlign(0, 1).setColor(g.theme.fg) // bottom center
g.drawString(footer, Bangle.appRect.x+Bangle.appRect.w/2, Bangle.appRect.y2); .drawString(footer, Bangle.appRect.x+Bangle.appRect.w/2, Bangle.appRect.y2);
if (messageNum < Bangle.MESSAGES.length - 1 && msgBoxes[messageNum].bottom) if (messageNum < Bangle.MESSAGES.length - 1 && msgBoxes[messageNum].bottom)
g.drawString("\0"+atob("CAiBAABBIhRJIhQI"), Bangle.appRect.x+Bangle.appRect.w/2-fw/2 - 20, Bangle.appRect.y2); // v swipe to next g.drawString("\0"+atob("CAiBAABBIhRJIhQI"), Bangle.appRect.x+Bangle.appRect.w/2-fw/2 - 20, Bangle.appRect.y2); // v swipe to next
if (messageNum > 0 && msgBoxes[messageNum].top) if (messageNum > 0 && msgBoxes[messageNum].top)
g.drawString("\0"+atob("CAiBABAoRJIoRIIA"), Bangle.appRect.x+Bangle.appRect.w/2+fw/2 + 20, Bangle.appRect.y2); // ^ swipe to prev g.drawString("\0"+atob("CAiBABAoRJIoRIIA"), Bangle.appRect.x+Bangle.appRect.w/2+fw/2 + 20, Bangle.appRect.y2); // ^ swipe to prev
// right hint: swipe from right for message actions // right hint: swipe from right for message actions
g.setFontAlign(1, 1) // bottom right g.setFontAlign(1, 1).setColor(1, 0.25, 0.25) // bottom right
.drawString( .drawString("<<", Bangle.appRect.x2 - 1, Bangle.appRect.y2)
//"\0"+atob("CAiBABIkSJBIJBIA"), // << .setColor(g.theme.fg);
"<<",
Bangle.appRect.x2 - 1, Bangle.appRect.y2
);
}; };
const refresh = function() { const refresh = function() {
@ -317,8 +365,8 @@ const showText = function(messageNum) {
msgBoxes[messageNum].draw(); msgBoxes[messageNum].draw();
msgBoxes[messageNum + 1].draw(); msgBoxes[messageNum + 1].draw();
drawFooter(); drawFooter();
multiplier *= 2; multiplier *= 2.5;
timeouts.animID = setTimeout(animate, delay); timeouts["animID"] = setTimeout(animate, delay);
} }
}; };
animate(); animate();
@ -352,8 +400,8 @@ const showText = function(messageNum) {
msgBoxes[messageNum].draw(); msgBoxes[messageNum].draw();
msgBoxes[messageNum - 1].draw(); msgBoxes[messageNum - 1].draw();
drawFooter(); drawFooter();
multiplier *= 2; multiplier *= 2.5;
timeouts.animID = setTimeout(animate, delay); timeouts["animID"] = setTimeout(animate, delay);
} }
}; };
animate(); animate();
@ -361,17 +409,19 @@ const showText = function(messageNum) {
}; };
const drawLeftBackground = function() { const drawLeftBackground = function() {
g.setBgColor(1, 0.5, 0); // red //g.setBgColor(1, 0.5, 0); // red
g.setClipRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2); g.setBgColor(g.theme.bg)
g.clearRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2); .setClipRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2)
g.setBgColor(g.theme.bg); .clearRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2)
.setBgColor(g.theme.bg);
}; };
const drawRightBackground = function() { const drawRightBackground = function() {
g.setBgColor(0, 0.5, 1); // red //g.setBgColor(0, 0.5, 1); // red
g.setClipRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2); g.setBgColor(g.theme.bg)
g.clearRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2); .setClipRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2)
g.setBgColor(g.theme.bg); .clearRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2)
.setBgColor(g.theme.bg);
}; };
const animateToLeft = function() { const animateToLeft = function() {
@ -379,18 +429,20 @@ const showText = function(messageNum) {
clearTimeout(timeouts.animID); clearTimeout(timeouts.animID);
timeouts.animID = undefined; timeouts.animID = undefined;
} }
const endX = Bangle.appRect.x + (Bangle.appRect.w / 2); let multiplier = 1;
const endX = Bangle.appRect.x - Bangle.appRect.w; //+ (Bangle.appRect.w / 2);
const msgBox = msgBoxes[messageNum]; const msgBox = msgBoxes[messageNum];
return new Promise((resolve, _reject) => { return new Promise((resolve, _reject) => {
let animate = () => { let animate = () => {
msgBox.xOffset -= step; msgBox.xOffset -= step * multiplier;
multiplier *= 2.5;
drawLeftBackground(); drawLeftBackground();
if (msgBox.xOffset <= endX) { if (msgBox.xOffset <= endX) {
return resolve(); return resolve();
} else { } else {
msgBox.draw(); msgBox.draw();
drawFooter(); drawFooter();
timeouts.animID = setTimeout(animate, delay); timeouts["animID"] = setTimeout(animate, delay);
} }
}; };
animate(); animate();
@ -402,18 +454,20 @@ const showText = function(messageNum) {
clearTimeout(timeouts.animID); clearTimeout(timeouts.animID);
timeouts.animID = undefined; timeouts.animID = undefined;
} }
const endX = Bangle.appRect.x2 - (Bangle.appRect.w / 2); let multiplier = 1;
const endX = Bangle.appRect.x2; // - (Bangle.appRect.w / 2);
const msgBox = msgBoxes[messageNum]; const msgBox = msgBoxes[messageNum];
return new Promise((resolve, _reject) => { return new Promise((resolve, _reject) => {
let animate = () => { let animate = () => {
msgBox.xOffset += step; msgBox.xOffset += step * multiplier;
multiplier *= 2.5;
drawRightBackground(); drawRightBackground();
if (msgBox.xOffset >= endX) { if (msgBox.xOffset >= endX) {
return resolve(); return resolve();
} else { } else {
msgBox.draw(); msgBox.draw();
drawFooter(); drawFooter();
timeouts.animID = setTimeout(animate, delay); timeouts["animID"] = setTimeout(animate, delay);
} }
}; };
animate(); animate();
@ -421,7 +475,7 @@ const showText = function(messageNum) {
}; };
let firstTouch = true; let firstTouch = true;
const handler = function(e) { const dragHandler = function(e) {
if (e.b === 0) { if (e.b === 0) {
firstTouch = true; firstTouch = true;
checkForNewMessages(); checkForNewMessages();
@ -438,28 +492,30 @@ const showText = function(messageNum) {
msgBoxes[messageNum].clearNew(); msgBoxes[messageNum].clearNew();
if (Math.abs(e.dy) > Math.abs(e.dx)) { if (Math.abs(e.dy) > Math.abs(e.dx)) {
firstTouch = false; firstTouch = false;
if (e.dy > 0 && msgBoxes[messageNum].top) { if (e.dy > 0 && msgBoxes[messageNum].top && messageNum > 0) {
mode = "prev"; mode = "prev";
} else if (msgBoxes[messageNum].bottom) { // e.dy will be < 0 here } else if (e.dy < 0 && msgBoxes[messageNum].bottom && messageNum + 1 < msgBoxes.length) { // e.dy will be < 0 here
mode = "next"; mode = "next";
} else { } else {
mode = "scroll"; mode = "scroll";
} }
} else if (Math.abs(e.dx) > Math.abs(e.dy)) { }
firstTouch = false; // } else if (Math.abs(e.dx) > Math.abs(e.dy)) {
if (e.dx < 0) { // firstTouch = false;
mode = "left"; // if (e.dx < 0) {
} else { // mode = "left";
mode = "right"; // } else {
} // mode = "right";
} else { // }
// } else {
else {
mode = undefined; mode = undefined;
return; return;
} }
} }
if (mode == "scroll") scrollHandler(e); if (mode == "scroll") scrollHandler(e);
else if (mode == "left") leftHandler(e); // remove from phone and watch //else if (mode == "left") leftHandler(e); // remove from phone and watch
else if (mode == "right") rightHandler(e); // remove from watch only //else if (mode == "right") rightHandler(e); // remove from watch only
else if (mode == "next") nextHandler(e); else if (mode == "next") nextHandler(e);
else if (mode == "prev") prevHandler(e); else if (mode == "prev") prevHandler(e);
}; };
@ -484,14 +540,20 @@ const showText = function(messageNum) {
}); });
}; };
const swipeHandler = function(dir) {
if (dir > 0) return rightHandler();
else if (dir < 0) return leftHandler();
else return;
};
const leftHandler = function(e) { const leftHandler = function(e) {
const msgBox = msgBoxes[messageNum]; const msgBox = msgBoxes[messageNum];
if (e.b == 0) { // if (e.b == 0) {
if (msgBox.xOffset > -swipeThreshold) { // if (msgBox.xOffset > -swipeThreshold) {
msgBox.xOffset = 0; // msgBox.xOffset = 0;
msgBox.draw(); // msgBox.draw();
drawFooter(); // drawFooter();
} else { // } else {
switching = true; switching = true;
animateToLeft().then(() => { animateToLeft().then(() => {
g.setBgColor(g.theme.bg); g.setBgColor(g.theme.bg);
@ -499,38 +561,38 @@ const showText = function(messageNum) {
removeMessage(); removeMessage();
switching = false; switching = false;
}); });
} // }
return; // return;
} // }
msgBox.xOffset += e.dx; // msgBox.xOffset += e.dx;
if (msgBox.xOffset > 0) msgBox.xOffset = 0; // if (msgBox.xOffset > 0) msgBox.xOffset = 0;
drawLeftBackground(); // drawLeftBackground();
msgBox.draw(); // msgBox.draw();
drawFooter(); // drawFooter();
}; };
const rightHandler = function(e) { const rightHandler = function(e) {
const msgBox = msgBoxes[messageNum]; const msgBox = msgBoxes[messageNum];
if (e.b == 0) { // if (e.b == 0) {
if (msgBox.xOffset < swipeThreshold) { // if (msgBox.xOffset < swipeThreshold) {
msgBox.xOffset = 0; // msgBox.xOffset = 0;
msgBox.draw(); // msgBox.draw();
drawFooter(); // drawFooter();
} else { // } else {
switching = true; switching = true;
animateToRight().then(() => { animateToRight().then(() => {
g.setBgColor(g.theme.bg); g.setBgColor(g.theme.bg);
removeMessage(); removeMessage();
switching = false; switching = false;
}); });
} // }
return; // return;
} // }
msgBox.xOffset += e.dx; // msgBox.xOffset += e.dx;
if (msgBox.xOffset < 0) msgBox.xOffset = 0; // if (msgBox.xOffset < 0) msgBox.xOffset = 0;
drawRightBackground(); // drawRightBackground();
msgBox.draw(); // msgBox.draw();
drawFooter(); // drawFooter();
}; };
const scrollHandler = function(e) { const scrollHandler = function(e) {
@ -541,7 +603,8 @@ const showText = function(messageNum) {
Bangle.setUI({ Bangle.setUI({
mode: "custom", mode: "custom",
drag: e => handler(e), drag: e => dragHandler(e),
swipe: dir => swipeHandler(dir),
btn: _e => goBack(), btn: _e => goBack(),
remove: cleanup remove: cleanup
}); });
@ -557,7 +620,7 @@ const checkForNewMessages = function(idleTime) {
idleTime = idleTime ?? 3000; // how much time without interaction before we are considered idle idleTime = idleTime ?? 3000; // how much time without interaction before we are considered idle
idle = false; idle = false;
if (timeouts.idleTimer) clearTimeout(timeouts.idleTimer); if (timeouts.idleTimer) clearTimeout(timeouts.idleTimer);
timeouts.idleTimer = setTimeout(() => { timeouts["idleTimer"] = setTimeout(() => {
if (haveNewMessage) { if (haveNewMessage) {
haveNewMessage = false; haveNewMessage = false;
let idx = Bangle.MESSAGES.findIndex(m => !m.handled); let idx = Bangle.MESSAGES.findIndex(m => !m.handled);
@ -580,17 +643,19 @@ const setBusy = function() {
timeouts.idleTimer = undefined; timeouts.idleTimer = undefined;
}; };
const goBack = function(timedOut) { // TODO do we want this as a stack or by priority? const goBack = function(timedOut) {
console.log("goBack()");
idle = true; idle = true;
if (buzzing) require("messages").stopBuzz(); if (buzzing) require("messages").stopBuzz();
let backTo; let backTo;
if (previous && previous.length) { if (previous && previous.length) {
backTo = previous.pop(); backTo = previous.pop();
clearTimeouts();
} else { } else {
if (!timedOut) Bangle.MESSAGES.forEach((m) => {if (!m.new) m.show = false;}); if (!timedOut) Bangle.MESSAGES.forEach((m) => {if (!m.new) m.show = false;});
require("messages").write(Bangle.MESSAGES); require("messages").write(Bangle.MESSAGES);
cleanup = _cleanup; cleanup = _cleanup;
Bangle.showClock(); Bangle.load();
} }
//console.log("backTo = ", backTo); //console.log("backTo = ", backTo);
switch (backTo) { switch (backTo) {
@ -676,7 +741,6 @@ const showMessage = function() {
idx = Bangle.MESSAGES.findIndex(m => !m.handled); idx = Bangle.MESSAGES.findIndex(m => !m.handled);
if (idx >= 0) { if (idx >= 0) {
Bangle.MESSAGES.every(m => m.handled = true); // set all text messages as handled Bangle.MESSAGES.every(m => m.handled = true); // set all text messages as handled
//for (let m of Bangle.MESSAGES) m.handled = true; // set all text messages as handled
setActive("text"); setActive("text");
return showText(idx); return showText(idx);
} }
@ -688,7 +752,6 @@ const showMessage = function() {
saveMessages = function() { saveMessages = function() {
require("messages").write(Bangle.MESSAGES); require("messages").write(Bangle.MESSAGES);
}; };
//E.on("kill", events.saveMessages);
setListener("kill", saveMessages); setListener("kill", saveMessages);
Bangle.loadWidgets(); Bangle.loadWidgets();

View File

@ -1,3 +1,8 @@
let timeouts = {};
const goBack = function() {};
const cleanup = function() {};
const showCall = function(call) { const showCall = function(call) {
const incomingImg = require("heatshrink").decompress(atob("j0ewIQNgwDCnEAh0B4EAvEOgEB+F//kP4P/+E/weAgH+g8Agf4CQMH8EYgEfEYU8AYV4AQIhBAYMD8ADBg4vBgEPzwDBj/+AYM/AYV//ADCC4X/EwQiCABo=")); const incomingImg = require("heatshrink").decompress(atob("j0ewIQNgwDCnEAh0B4EAvEOgEB+F//kP4P/+E/weAgH+g8Agf4CQMH8EYgEfEYU8AYV4AQIhBAYMD8ADBg4vBgEPzwDBj/+AYM/AYV//ADCC4X/EwQiCABo="));
const outgoingImg = require("heatshrink").decompress(atob("j0ewIRO4ACBgeAh0Ag8AvEAh0B+F//kP4P/+E/wASB/0AjkD/EA8EH8EDgEfEwU8AYQhBgAhBFwXgAYMHGwUPzwDBj4mBgE/AYV/FQIDBC4X/EwQiCABoA==")); const outgoingImg = require("heatshrink").decompress(atob("j0ewIRO4ACBgeAh0Ag8AvEAh0B+F//kP4P/+E/wASB/0AjkD/EA8EH8EDgEfEwU8AYQhBgAhBFwXgAYMHGwUPzwDBj4mBgE/AYV/FQIDBC4X/EwQiCABoA=="));
@ -18,35 +23,38 @@ const showCall = function(call) {
const headerBox = new HeaderBox(msg, Bangle.appRect); const headerBox = new HeaderBox(msg, Bangle.appRect);
const x = Bangle.appRect.x, y = Bangle.appRect.y + headerBox.h, x2 = Bangle.appRect.x2, y2 = Bangle.appRect.y2; const x = Bangle.appRect.x, y = Bangle.appRect.y + headerBox.h, x2 = Bangle.appRect.x2, y2 = Bangle.appRect.y2;
const mx = (x + x2) / 2; const mx = (x + x2) / 2;
let timerInt; //TODO deal with this
headerBox.draw(Bangle.appRect); headerBox.draw(Bangle.appRect);
g.reset(); g.reset();
const drawLeftArrow = function(imgX) { const drawAcceptArrow = function(xOffset) {
imgX = imgX ?? x+2; xOffset = xOffset??0;
g.setColor(1 ,0.25, 0.25); imgX = x + 2 + xOffset;
g.drawImage(leftImg, imgX, y2-50);
};
const drawRightArrow = function(imgX) {
imgX = imgX ?? x2-50;
g.setColor(0, 1, 0); g.setColor(0, 1, 0);
g.drawImage(rightImg, imgX, y2-50); g.drawImage(rightImg, imgX, y2-50);
if (xOffset > 0) g.fillRect(imgX+3, y2-43, x, y2-9);
};
const drawRejectArrow = function(xOffset) {
xOffset = xOffset??0;
let imgX = x2 - 50 - xOffset;
g.setColor(1, 0.25, 0.25);
g.drawImage(leftImg, imgX, y2-50);
if (xOffset > 0) g.fillRect(imgX+45, y2-43, x2, y2-9);
}; };
if (cmd === "end") { if (cmd === "end") {
if (timerInt) clearTimeout(timerInt); //TODO change timerInt variable if (timeouts.timer) clearTimeout(timeouts.timer);
g.setColor(g.theme.fg).setFont("6x15:2").setFontAlign(0, -1); g.setColor(g.theme.fg).setFont("6x15:2").setFontAlign(0, -1);
g.drawString("Call Ended", mx, y+25); g.drawString("Call Ended", mx, y+25);
endTimeout = setTimeout(() => g.clear(), 3000); timeouts["endTimeout"] = setTimeout(() => g.clear(), 3000);
} }
if (cmd === "incoming") { if (cmd === "incoming") {
drawLeftArrow(); drawRejectArrow();
drawRightArrow(); drawAcceptArrow();
g.setColor(0,1,0); g.setColor(0,1,0);
g.drawImage(ringingImg, mx-25, y+15); g.drawImage(ringingImg, mx-25, y+15);
} }
if (cmd === "start" || cmd === "outgoing") { if (cmd === "start" || cmd === "outgoing") {
drawLeftArrow(x2 - 52); drawRejectArrow();
startTime = parseInt(Date.now()/1000); startTime = parseInt(Date.now()/1000);
g.setColor(g.theme.fg); g.setColor(g.theme.fg);
g.drawImage(cmd === "start" ? incomingImg : outgoingImg, x+10, y+20); g.drawImage(cmd === "start" ? incomingImg : outgoingImg, x+10, y+20);
@ -57,25 +65,57 @@ const showCall = function(call) {
const m = ("0" + Math.floor((elapsed/60)%60)).slice(-2); const m = ("0" + Math.floor((elapsed/60)%60)).slice(-2);
const s = ("0" + Math.floor(elapsed%60)).slice(-2); const s = ("0" + Math.floor(elapsed%60)).slice(-2);
g.setFont("Vector:25").setFontAlign(0, -1).drawString(`${h}:${m}:${s}`, mx + 15, y+25); g.setFont("Vector:25").setFontAlign(0, -1).drawString(`${h}:${m}:${s}`, mx + 15, y+25);
timerInt = setTimeout(timer, 1000); //TODO put into intervals object timeouts["timer"] = setTimeout(timer, 1000);
}; };
timer(); timer();
} }
const handler = function(dir) { const handler = function(dir) {
if (cmd === "end") return;
if (dir < 0) leftHandler(dir);
else if (dir > 0 && cmd === "incoming") rightHandler();
};
} const leftHandler = function(dir) {
let xOff = 0;
const swipeAnimation = () => {
xOff += 30;
g.clearRect(x, y2-50, x2, y2);
drawRejectArrow(xOff);
if (xOff > 160) return;
else setTimeout(swipeAnimation, 30);
}
swipeAnimation();
if (timeouts.timer) clearTimeout(timeouts.timer);
return Bangle.messageResponse(msg, false);
};
const rightHandler = function(dir) {
let xOff = 0;
const swipeAnimation = () => {
xOff += 30;
g.clearRect(x, y2-50, x2, y2);
drawAcceptArrow(xOff);
if (xOff > 160) return;
else setTimeout(swipeAnimation, 30);
}
swipeAnimation();
if (timeouts.timer) clearTimeout(timeouts.timer);
return Bangle.messageResponse(msg, true);
};
Bangle.setUI({ Bangle.setUI({
mode: "custom", mode: "custom",
touch: () => {if (buzzing) return require("messages".stopBuzz())},
swipe: handler, swipe: handler,
btn: () => {clearInterval(timerInt)} btn: _e => goBack(),
remove: cleanup
}); });
}; };
let msg = {"t":"call","cmd":"start","name":"","number":"1306-7740297","id":"call","src":"Phone","positive":true,"negative":true,"title":"Hayley Thiessen, Wifey","body":"Incoming call\n13067740297","new":true,"show":true,"type":"call"} let msg = {"t":"call","cmd":"incoming","name":"","number":"1306-7740297","id":"call","src":"Phone","positive":true,"negative":true,"title":"Hayley Thiessen, Wifey","body":"Incoming call\n13067740297","new":true,"show":true,"type":"call"}
g.reset(); g.reset();
showCall(msg); showCall(msg);

View File

@ -7,7 +7,7 @@ exports.messageListener = function(type, msg) {
if (!Bangle.MESSAGES || !Bangle.MESSAGES.length) Bangle.MESSAGES = require("messages").getMessages(msg); if (!Bangle.MESSAGES || !Bangle.MESSAGES.length) Bangle.MESSAGES = require("messages").getMessages(msg);
msg.show = true; msg.show = true;
msg.type = type; msg.type = type;
if (msg.id === "call" && msg.t === "remove" && msg.cmd != "end") { if (msg.id === "call" && msg.t === "remove") {
msg.t = "modify"; // not sure why messages module puts everything as remove except for "incoming" msg.t = "modify"; // not sure why messages module puts everything as remove except for "incoming"
msg.new = true; msg.new = true;
} }