From 418ce714f947cae8c4497df43a84c3741da803b8 Mon Sep 17 00:00:00 2001 From: Francesco Bedussi Date: Sat, 2 May 2020 13:45:22 +0200 Subject: [PATCH] feat: add timer app --- apps.json | 21 ++++++ apps/timer/ChangeLog | 1 + apps/timer/README.md | 16 +++++ apps/timer/app-icon.js | 5 ++ apps/timer/app.js | 151 +++++++++++++++++++++++++++++++++++++++++ apps/timer/app.png | Bin 0 -> 2107 bytes 6 files changed, 194 insertions(+) create mode 100644 apps/timer/ChangeLog create mode 100644 apps/timer/README.md create mode 100644 apps/timer/app-icon.js create mode 100644 apps/timer/app.js create mode 100644 apps/timer/app.png diff --git a/apps.json b/apps.json index e9e38a1a1..c57d94958 100644 --- a/apps.json +++ b/apps.json @@ -1550,5 +1550,26 @@ {"name":"hidjoystick.app.js","url":"app.js"}, {"name":"hidjoystick.img","url":"app-icon.js","evaluate":true} ] + }, + { + "id": "timer", + "name": "Timer", + "icon": "app.png", + "version": "0.01", + "description": "Simple timer, useful when playing board games or cooking", + "tags": "timer", + "readme": "README.md", + "allow_emulator": true, + "storage": [ + { + "name": "timer.app.js", + "url": "app.js" + }, + { + "name": "timer.img", + "url": "app-icon.js", + "evaluate": true + } + ] } ] diff --git a/apps/timer/ChangeLog b/apps/timer/ChangeLog new file mode 100644 index 000000000..ec66c5568 --- /dev/null +++ b/apps/timer/ChangeLog @@ -0,0 +1 @@ +0.01: Initial version diff --git a/apps/timer/README.md b/apps/timer/README.md new file mode 100644 index 000000000..9326e510d --- /dev/null +++ b/apps/timer/README.md @@ -0,0 +1,16 @@ +# Timer + +Simple timer, useful when playing board games or cooking + +## Features + +- When the time is up the timer can be reset to starting time, this is useful e.g. for playing board games +- When the countdown is running the timer cannot be adjusted, this prevents accidental time variations +- When the time is up the starting time is shown, as a reminder of the time elapsed + +## How to use it + +- Tap on minutes to increase them one by one +- Tap on seconds to increase them one by one +- Press BTN3 to reset time to 0 +- Press BTN1 to start the timer or reset to the original time diff --git a/apps/timer/app-icon.js b/apps/timer/app-icon.js new file mode 100644 index 000000000..b55486dd1 --- /dev/null +++ b/apps/timer/app-icon.js @@ -0,0 +1,5 @@ +require("heatshrink").decompress( + atob( + "mEwxH+AH4A/AEsxAAQso1eyrgvDrmrw4skAAQuDAAIHBrYABFsQvMGLYtGAAOAFweA2WrF4gwYFxAwEFwIvBwowFsIub64AB6wJF6wJB1mGMTFbrmsEYoADHAwAC1dhGCoTCmJhBEYoAM2RiFF6VbleBF6QABGAguSw2sgAwnCAdhXYIwBqwvT2WFDwYvP1YZCwMAlYwT1ZgORogZEqwwB1iRhBoYmGlcAYiZgOBgWFDIzCBAALESYIYvMw4ZHGCuHF5aOKeYgABYiCQMBYeyDZLzBAAQwO2QvPDhbzCeqAvbGAQQBlYvqeYIvteYMreJ7vaACbvQJxwAP1YvLGAeHF7uHFxYvDwovdwovPSDusRxgvEwwvbwwvNGAmrds4vGsOyFy+ysIvPSLqNPGDwuT/xyEwySS2QuEF6BgEYYL0Q1ZIEFyIwGMQIxM1ZcFFyYwHreFw+rSwmy1eHwoSGFygxJABwtXeo4upMSQtdGZorjAH4A/AF4A==" + ) +) diff --git a/apps/timer/app.js b/apps/timer/app.js new file mode 100644 index 000000000..dadbdb825 --- /dev/null +++ b/apps/timer/app.js @@ -0,0 +1,151 @@ +let counter = 0; +let setValue = 0; +let counterInterval; +let state; + +const DEBOUNCE = 50; + +function buzzAndBeep() { + return Bangle.buzz(1000, 1) + .then(() => Bangle.beep(200, 3000)) + .then(() => setTimeout(buzzAndBeep, 5000)); +} + +function outOfTime() { + g.clearRect(0, 0, 220, 70); + g.setFontAlign(0, 0); + g.setFont("6x8", 3); + g.drawString("Time UP!", 120, 50); + counter = setValue; + buzzAndBeep(); + setInterval(() => { + g.clearRect(0, 70, 220, 160); + setTimeout(draw, 200); + }, 400); + state = "stopped"; +} + +function draw() { + const minutes = Math.floor(counter / 60); + const seconds = Math.floor(counter % 60); + const seconds2Digits = seconds < 10 ? `0${seconds}` : seconds.toString(); + g.clearRect(0, 70, 220, 160); + g.setFontAlign(0, 0); + g.setFont("6x8", 7); + g.drawString( + `${minutes < 10 ? "0" : ""}${minutes}:${seconds2Digits}`, + 120, + 120 + ); +} + +function countDown() { + if (counter <= 0) { + if (counterInterval) { + clearInterval(counterInterval); + counterInterval = undefined; + } + outOfTime(); + return; + } + + counter--; + draw(); +} + +function clearIntervals() { + clearInterval(); + counterInterval = undefined; +} + +function set(delta) { + if (state === "started") return; + counter += delta; + if (state === "unset") { + state = "set"; + } + draw(); + g.flip(); +} + +function startTimer() { + setValue = counter; + countDown(); + counterInterval = setInterval(countDown, 1000); +} + +// unset -> set -> started -> -> stopped -> set +const stateMap = { + set: () => { + state = "started"; + startTimer(); + }, + started: () => { + reset(setValue); + }, + stopped: () => { + reset(setValue); + } +}; + +function changeState() { + if (stateMap[state]) stateMap[state](); +} + +function drawLabels() { + g.clear(); + g.setFontAlign(-1, 0); + g.setFont("6x8", 7); + g.drawString(`+ +`, 35, 180); + g.setFontAlign(0, 0, 3); + g.setFont("6x8", 1); + g.drawString(`reset (re)start`, 230, 120); +} + +function reset(value) { + clearIntervals(); + counter = value; + setValue = value; + drawLabels(); + draw(); + state = value === 0 ? "unset" : "set"; +} + +function addWatch() { + clearWatch(); + setWatch(changeState, BTN1, { + debounce: DEBOUNCE, + repeat: true, + edge: "falling" + }); + setWatch( + () => { + reset(0); + }, + BTN3, + { + debounce: DEBOUNCE, + repeat: true, + edge: "falling" + } + ); + setWatch( + () => { + set(60); + }, + BTN4, + { + debounce: DEBOUNCE, + repeat: true, + edge: "falling" + } + ); + setWatch(() => set(1), BTN5, { + debounce: DEBOUNCE, + repeat: true, + edge: "falling" + }); +} + +reset(0); +addWatch(); diff --git a/apps/timer/app.png b/apps/timer/app.png new file mode 100644 index 0000000000000000000000000000000000000000..f593a3a8bd3f5f87032a6b575bf2432085468a11 GIT binary patch literal 2107 zcmV-B2*me^P)XJ=kQ@6U^OIn&x`%j5jwTW9>b`e1rGrF7ItUzE*SLCs3wMr0e5!fh5fC1)p z@97`NcxUDgGXt}K)$gCl?>pyr&-dMP=bU?f7kG)6m>0+oana>Fm#fq<XQAXA?d%MlQ}^7}kFR0ES_n|GI`urodsR z$o%q%IsXg~=|iEQc_>&dOt1-G+^symJZjaylcUpoirCp8#QDZrv~;z&#J`=t3mnIx=SdfC zJh}p#bJB+*dg@8S*n6k5I~*Z1aO}$>eeU9Iy$O-2@t$owt3i~;h%i+Q2x0JSst+Sm z1B%y)(k3BVn+%6&!>#^Cv_7c8@I=2-*UvfVcM1h&A1+_O?*sf!dlt`*+Alu1J+Lx0 zaTzokH2{DR1~Ix6#D^_{n$v@j>3gB&BcS2JAW{b;>I5MSG<-PX^b4^-J?)=mI2a?A zAZK9#)SM3gd3GBT73IS&kzik)|7K2YbKPALv%s%`HwrRN5nvbe7Mwfz6&5c{gTasp zV|WJiswfbJN#t1#!qstz(i#z^H6mOc2cFe<^B$5*aT10P)662q|cG63BS7ax&=4}M;Wx8B?ZQ52DvmlrAzP;+{u8**{0 zztL?b2#}w@_eW=%YaS{7AAByO42M4eh@FW!Mupv3A7R;&*HB$ujiX18V*mdAu-ilT zcCbJbhoV*G;90etj&=~X%vX-$3<#fZN~V;2EN|bMu^-D4rti4PWP(noLq$aenwpxh zefxIk_4<&Q2-n0wq7ohsf9K)|@ZvqaWSr4yN2xSY;<;ZhQt5>tTVlZFm<$?Qi+h>RqE?yKoA551pDON`o+7!5bw!4 zapDAWa&pku*N2T8H=?1TVV=^TtL3!VytK%Tqd?Kl^E8=6>3f=r;?UxhqL?|kO(%*<21t>&p(wL zj7B5s>gu3UsX!@3Sy>tO?Ae3KNxz%utWdEUERA2~NqgN%F9Qsv+49&Flj(P`wQJYn z+1_tuOdvb?qd_c{|r!IsXR_tuqdFxii?X;Qc~iIySlotX3ZM3 zwY3E(*Bgd#lP8ttNhqyCiSi&ymk{uPm6erlo7=#^0M@Nr2ea8cOO|g$>x{E%1C$Mf z$pbYP`1-C=sZd{EkCc=Y0Kmb&nLtUX&6$E;RJl?Me+CBSt|A{5BQ6AoZ@-6J5HN?{V!!BCU{nULAArfiy z?B`{G@7&Y|P}de}cTVAUf71^layH!RzY4oke#FFo+0OMHp8b^GMkNCBiJWVFPy>-V zL$A^YM9GPko*EC9e4oRV8nZkUJU^Gxj1fbhnb&j=y!$vKPd8LDsm24mLHn;4yX zinG^$jWMfxeU}ovJ6q9r*1Ay3rw{+NVc)_;fVj>G7TXAJKK>fXQ5lHT8s;q=n0{KWjewXx2BufQq|+)_o^4_3Xl!0ugq6u#p;9Ox zD#0#VajXApwDg=)xa$Cb%N+E(0x9kWTwZ^tJ&TVUjHo2Q0i|{or$t))YNWNtHXkksX+{m_Mmt8J9Iy}?zu_HK&!Yg`o6HaIiQUv=ub>X%v*L5(BqI* z?Lvg7l;9WT+Z*eGNecQvQ(kbjR&Z6%WkwBi|8oei8#5 zq@eo%k`i1t?E{!<3R>lBlL`bO`OGQ^0^`VP$p(=By!4R<_#dq_lLC3A1;_vZ002ovPDHLkV1jSd^+o^y literal 0 HcmV?d00001