diff --git a/apps.json b/apps.json index 56c984034..0e271adcf 100644 --- a/apps.json +++ b/apps.json @@ -4540,8 +4540,39 @@ "storage": [ {"name":"poweroff.app.js","url":"app.js"}, {"name":"poweroff.img","url":"app-icon.js","evaluate":true} - ] - }, + ] +}, +{ + "id": "sensible", + "name": "SensiBLE", + "shortName": "SensiBLE", + "version": "0.02", + "description": "Collect, display and advertise real-time sensor data.", + "icon": "sensible.png", + "type": "app", + "tags": "tool,sensors", + "supports" : [ "BANGLEJS2" ], + "allow_emulator": true, + "readme": "README.md", + "storage": [ + { "name": "sensible.app.js", "url": "sensible.js" }, + { "name": "sensible.img", "url": "sensible-icon.js", "evaluate": true } + ] +}, +{ + "id":"a_speech_timer", + "name":"A Speech Timer", + "icon": "app.png", + "version":"1.00", + "description": "A timer designed to help keeping your speeches and presentations to time.", + "tags": "tool,timer", + "readme":"README.md", + "supports":["BANGLEJS2"], + "storage": [ + {"name":"a_speech_timer.app.js","url":"app.js"}, + {"name":"a_speech_timer.img","url":"app-icon.js","evaluate":true} + ] +}, { "id": "sensible", "name": "SensiBLE", diff --git a/apps/a_speech_timer/ChangeLog b/apps/a_speech_timer/ChangeLog new file mode 100644 index 000000000..4a8e3fbe7 --- /dev/null +++ b/apps/a_speech_timer/ChangeLog @@ -0,0 +1 @@ +1.00: Release (2021/12/01) diff --git a/apps/a_speech_timer/README.md b/apps/a_speech_timer/README.md new file mode 100644 index 000000000..098c352f3 --- /dev/null +++ b/apps/a_speech_timer/README.md @@ -0,0 +1,16 @@ +# A Speech Timer + +* A timer designed to help keeping your speeches and presentations to time +* Vibrates 1-2-3 times and changes screen color within the target time range. + * Example for a 5 to 7 minutes speech: vibrates once at 5:00 (green), twice at 6:00 (yellow), thrice at 7:00 (red). +* Use the buttons to start a timer +* Swipe left or right to choose different target times +* Touching the timer on the upper part of the screen locks (or unlocks) the buttons to prevent accidental changes + +![](screenshot0.png) +![](screenshot1.png) +![](screenshot2.png) +![](screenshot3.png) + +## Creator +[@alainsaas](https://github.com/alainsaas) diff --git a/apps/a_speech_timer/app-icon.js b/apps/a_speech_timer/app-icon.js new file mode 100644 index 000000000..1fdb2c509 --- /dev/null +++ b/apps/a_speech_timer/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgP//kAj//AAP5/+PApH7//PAonvAoXzAonj//nApHggEHAoWAgA5BAAJCCAoU/IYIFCv///w0CAonrv/HAoXLv+DAogLFgPeAoV+nlOAoV4/8+AoV79+eFIVzAof7u/v5xBCs4FL84FE//O74FBu4FB64FD73TAoNz/+eAoV5IIIFCvl8vwFCv8A/wFDO4IFFFIQFCGoSVFUIqtDh65D/1vYof+Y4LLDw7dD/0ndIYRCeoQFC/P/z/+i///oFBGoX8gEfAgI=")) diff --git a/apps/a_speech_timer/app.js b/apps/a_speech_timer/app.js new file mode 100644 index 000000000..dae2545b2 --- /dev/null +++ b/apps/a_speech_timer/app.js @@ -0,0 +1,173 @@ +Graphics.prototype.setFontMichroma36 = function() { +g.setFontCustom(atob("AAAAAAAAAAAAAAAAeAAAAAeAAAAAeAAAAAeAAAAAAAAAAAAAAAAAAAAAAAGAAAAA+AAAAD+AAAAP+AAAA/8AAAD/wAAAf/AAAB/4AAAH/gAAAf+AAAB/4AAAH/gAAAf+AAAAfwAAAAfAAAAAcAAAAAAAAAAAAAAAAAAAAAAAA///AAD///wAH///4AP///8APwAD+APAAAeAeAAAeAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAeAPAAAeAPwAD+AP///8AH///4AD///wAA///AAAAAAAAAAAAAAAAAAAAAEAAAAAOAAAAAfAAAAA+AAAAB8AAAAD8AAAAH4AAAAPwAAAAPgAAAAfAAAAAf///+Af///+Af///+Af///+AAAAAAAAAAAAAAAAAAAAAAAAAA/Af+AD/A/+AH/B/+AP/D/+APwD4eAPADweAfADweAeADweAeADweAeADweAeAHgeAeAHgeAeAHgeAeAHgeAeAHgeAeAHgeAeAHgeAeAHgeAeAHgeAeAHgeAeAPgeAeAPAeAeAPAeAeAPAeAeAPAeAfAPAeAPw/AeAP/+AeAH/+AeAD/8AeAB/wAOAAAAAAAAAAAAAAAAAAAAAAAAAB8APgAD8AP4AH8AP8AP8AP8APgAB+AfAAAeAeAAAeAeAAAPAeAAAPAeAAAPAeAAAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAeAfAeAeAPx/h+AP///+AH///8AD///4AB/h/gAAAAAAAAAAAAAAAAAAAAAAeAAAAA/AAAAA/AAAAB/AAAAD/AAAAH/AAAAPvAAAAPPAAAAfPAAAA+PAAAB8PAAAD4PAAADwPAAAHwPAAAPgPAAAfAPAAA+APAAA8APAAB8APAAD4APAAHwAPAAPgAPAAPAAPAAfAAPAAf///+Af///+Af///+Af///+AAAAPAAAAAPAAAAAPAAAAAPAAAAAOAAAAAAAAAAAAAAAAAAAAAAAAAAf/8PgAf/8P4Af/8P8Af/8P8AeB4A+AeB4AeAeDwAeAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAfAeDwAeAeD4A+AeD+D+AeB//8AeB//4AeA//4AAAP/AAAAAAAAAAAAAAAAAAAAAAAAAAA///AAD///wAH///4AH///8AP4fB+APAeAeAfA8AeAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAfA8APAPA+AeAPgeAeAP8fh+AH8f/8AD8P/8AA8H/4AAAB/gAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAeAAAAAeAAAAAeAAAAAeAAAAAeAAACAeAAAGAeAAAOAeAAAeAeAAA+AeAAD+AeAAH8AeAAP4AeAAfwAeAA/gAeAB/AAeAD+AAeAP4AAeAfwAAeA/gAAeB/AAAeD+AAAeH8AAAefwAAAe/gAAAf/AAAAf+AAAAf8AAAAf4AAAAfgAAAAfAAAAAAAAAAAAAAAAAAAAAAAAAAMAAB+B/wAD/j/4AH/3/8AP///+AP//A+AfB+AeAeA+AeAeA+APAeA+APAeA+APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA+APAeA+APAeA+APAeA+AOAeA+AeAPh/A+AP///+AP/3/8AH/3/8AB/D/wAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAD/4HAAH/8HwAP/+H4AP5/H8AfAfA8AeAPAeAeAPAeAeAPAeAeAHgfAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHAPAeAPAOAeAPAeAPAPAeAPwfB+AP///8AH///4AD///wAA///AAAAAAAAAAAAAAAAAAAAAAAAAAAB8DwAAB8HwAAB8HwAAB8DwAAAAAAAAAAAAA"), 46, atob("CBIkESMjJCMjIyMjCA=="), 36+(1<<8)+(1<<16)); +}; + +Graphics.prototype.setFontMichroma16 = function(scale) { +g.setFontCustom(atob("AAAAGAAYAAAAGAB4A/APwD4AeADgAAAAAAA/8H/4YBjAGMAcwBzAHMAcwBzAHMAYYBh/+D/wAAAAABgAOABwAGAA//h/+AAAAAA4+Hn4YZjhmMOYw5jDmMMYwxjDGOMYYxh/GD4YAAAAADBwcHhgGOAYwBzHHMccxxzHHMcc5xhnGH/4PfAAAAAAAOAB4APgB2AGYAxgHGA4YDBgYGD/+P/4AOAAYAAAAAD+cP547BjsGOwc7BzsHOwc7BzsHOwY7zjv+APgAAAAAD/wf/hmGOYYxhzGHMYcxhzGHOYYZhh3uDP4AeAAAEAA4ADgAOAI4DjgeODw4eDjgOcA7gD8APgA8AAAAAAAAAA58H/4bxjmGMYcxhzGHMYcxhzGHOYYbxh/+DnwAAAAADxgfnBnOOMYwxjDHMMcwxzDHMMY4xhjOH/4P/AAAAAABnAGcAAA"), 46, atob("BAgQCBAQEBAQEBAQBA=="), 16+(scale<<8)+(1<<16)); +}; + +function timeToString(duration) { + var hrs = ~~(duration / 3600); + var mins = ~~((duration % 3600) / 60); + var secs = ~~duration % 60; + var ret = ""; + if (hrs > 0) { + ret += "" + hrs + ":" + (mins < 10 ? "0" : ""); + } + ret += "" + mins + ":" + (secs < 10 ? "0" : ""); + ret += "" + secs; + return ret; +} + +var newtimer_left_from = 60; +var newtimer_left_to = 2*60; + +var newtimer_right_from = 5*60; +var newtimer_right_to = 7*60; + +var current_from = 5*60; +var current_mid = 6*60; +var current_to = 7*60; +var current_value = 0; + +var timerinterval; +var istimeron = false; + +var islocked = false; + +function countDown() { + current_value++; + draw(); + + if (current_value == current_from) { + Bangle.buzz(500); + } else if (current_value == current_mid) { + Bangle.buzz(400).then(()=>{ + return new Promise(resolve=>setTimeout(resolve, 800)); + }).then(()=>{ + return Bangle.buzz(500); + }); + } else if (current_value == current_to) { + Bangle.buzz(300).then(()=>{ + return new Promise(resolve=>setTimeout(resolve, 600)); + }).then(()=>{ + Bangle.buzz(300).then(()=>{ + return new Promise(resolve=>setTimeout(resolve, 600)); + }).then(()=>{ + return Bangle.buzz(500); + }); + }); + } + +} + +Bangle.on('touch',(touchside, touchdata)=>{ + if (!islocked && istimeron && touchdata.y > (100+10)) { + Bangle.buzz(40); + istimeron = false; + clearInterval(timerinterval); + } else if (touchdata.y > 24 && touchdata.y < (100-10)) { + Bangle.buzz(40); + islocked = !islocked; + } else if (!islocked && touchdata.y > (100+10) && touchdata.x > 88 + 10) { + Bangle.buzz(40); + current_from = newtimer_right_from; + current_to = newtimer_right_to; + current_mid = (current_from + current_to) / 2; + current_value = 0; + if (timerinterval) clearInterval(timerinterval); + timerinterval = setInterval(countDown, 1000); + istimeron = true; + } else if (!islocked && touchdata.y > (100+10) && touchdata.x < 88 - 10) { + Bangle.buzz(40); + current_from = newtimer_left_from; + current_to = newtimer_left_to; + current_mid = (current_from + current_to) / 2; + current_value = 0; + if (timerinterval) clearInterval(timerinterval); + timerinterval = setInterval(countDown, 1000); + istimeron = true; + } + showInstructions = false; + draw(); +}); + +Bangle.on('swipe',(swiperight, swipedown)=>{ + console.log(swiperight); + console.log(swipedown); + + if (swiperight == -1) { + if (newtimer_left_from >= 60) { + newtimer_left_from += 60; + newtimer_left_to += 60; + } else { // special case for 0:30 to 1:00 + newtimer_left_from = 60; + newtimer_left_to = 120; + } + newtimer_right_from += 60; + newtimer_right_to += 60; + draw(); + } else if (swiperight == 1) { + if (newtimer_left_from > 60) { + newtimer_left_from -= 60; + newtimer_left_to -= 60; + } else { // special case for 0:30 to 1:00 + newtimer_left_from = 30; + newtimer_left_to = 60; + } + + if (newtimer_right_from > 120) { + newtimer_right_from -= 60; + newtimer_right_to -= 60; + } + draw(); + } +}); + +var drawTimeout; +var showInstructions = true; + +function draw() { + g.reset(); + if (current_value >= current_to) { g.setBgColor("#F00"); } + else if (current_value >= current_mid) { g.setBgColor("#FF0"); } + else if (current_value >= current_from) { g.setBgColor("#8F8"); } + g.clearRect(0,24,176,176); + + g.reset(); + g.setFontAlign(0, 0); + + g.setFont("Michroma36").drawString(timeToString(current_value), 88, 62); + + g.setFont("HaxorNarrow7x17"); + g.drawString(timeToString(current_from), 44, 62+26); + g.drawString(timeToString(current_mid), 88, 62+26); + g.drawString(timeToString(current_to), 132, 62+26); + + if (current_value >= current_from) { g.drawRect(44-1,62+26+9,44+1,62+26+9+1); } + if (current_value >= current_mid) { g.drawRect(88-1,62+26+9,88+1,62+26+9+1); } + if (current_value >= current_to) { g.drawRect(132-1,62+26+9,132+1,62+26+9+1); } + + if (showInstructions) { + g.setFont("6x8").drawString("Tapping timer locks buttons", 88, 100+5); + g.setFont("6x8").drawString("<= Swipe to change time =>", 88, 168); + } + + g.setColor(islocked ? "#444" : "#000"); + g.setFont("Michroma16"); + g.drawString(timeToString(newtimer_left_from), 44, 138-9); + g.drawString(timeToString(newtimer_left_to), 44, 138+9); + g.drawString(timeToString(newtimer_right_from), 132, 138-9); + g.drawString(timeToString(newtimer_right_to), 132, 138+9); + + g.drawRect(0+8,138-24, 88-9+1, 138+22+1); + g.drawRect(0+8,138-24, 88-9, 138+22); + g.drawRect(88+8,138-24, 176-10+1, 138+22+1); + g.drawRect(88+8,138-24, 176-10, 138+22); +} + +require("FontHaxorNarrow7x17").add(Graphics); +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +draw(); diff --git a/apps/a_speech_timer/app.png b/apps/a_speech_timer/app.png new file mode 100644 index 000000000..1eb777fa7 Binary files /dev/null and b/apps/a_speech_timer/app.png differ diff --git a/apps/a_speech_timer/screenshot0.png b/apps/a_speech_timer/screenshot0.png new file mode 100644 index 000000000..ee3ababc1 Binary files /dev/null and b/apps/a_speech_timer/screenshot0.png differ diff --git a/apps/a_speech_timer/screenshot1.png b/apps/a_speech_timer/screenshot1.png new file mode 100644 index 000000000..69ea91e95 Binary files /dev/null and b/apps/a_speech_timer/screenshot1.png differ diff --git a/apps/a_speech_timer/screenshot2.png b/apps/a_speech_timer/screenshot2.png new file mode 100644 index 000000000..fd511e0f6 Binary files /dev/null and b/apps/a_speech_timer/screenshot2.png differ diff --git a/apps/a_speech_timer/screenshot3.png b/apps/a_speech_timer/screenshot3.png new file mode 100644 index 000000000..7b67b6f01 Binary files /dev/null and b/apps/a_speech_timer/screenshot3.png differ