From 151a51470bef712917cdca95f24d2cece5dd437e Mon Sep 17 00:00:00 2001 From: Shaylin Chetty Date: Sun, 21 Feb 2021 11:22:04 +0200 Subject: [PATCH] Added countdown timer application --- apps.json | 12 ++ apps/countdowntimer/ChangeLog | 1 + apps/countdowntimer/README.md | 12 ++ apps/countdowntimer/countdowntimer-icon.js | 1 + apps/countdowntimer/countdowntimer.js | 232 +++++++++++++++++++++ apps/countdowntimer/countdowntimer.png | Bin 0 -> 2663 bytes 6 files changed, 258 insertions(+) create mode 100644 apps/countdowntimer/ChangeLog create mode 100644 apps/countdowntimer/README.md create mode 100644 apps/countdowntimer/countdowntimer-icon.js create mode 100644 apps/countdowntimer/countdowntimer.js create mode 100644 apps/countdowntimer/countdowntimer.png diff --git a/apps.json b/apps.json index a7517fb27..84d465376 100644 --- a/apps.json +++ b/apps.json @@ -2855,5 +2855,17 @@ "storage": [ {"name":"widhrt.wid.js","url":"widget.js"} ] +}, +{ "id": "countdowntimer", + "name" : "Countdown Timer", + "icon": "countdowntimer.png", + "version": "0.01", + "description": "A simple countdown timer with a focus on usability", + "tags": "timer, tool", + "readme": "README.md", + "storage": [ + {"name": "countdowntimer.app.js", "url": "countdowntimer.js"}, + {"name": "countdowntimer.img", "url": "countdowntimer-icon.js", "evaluate": true} + ] } ] diff --git a/apps/countdowntimer/ChangeLog b/apps/countdowntimer/ChangeLog new file mode 100644 index 000000000..624f1b0fb --- /dev/null +++ b/apps/countdowntimer/ChangeLog @@ -0,0 +1 @@ +0.01: Initial version \ No newline at end of file diff --git a/apps/countdowntimer/README.md b/apps/countdowntimer/README.md new file mode 100644 index 000000000..3ad0eea84 --- /dev/null +++ b/apps/countdowntimer/README.md @@ -0,0 +1,12 @@ +# countdown-timer + +A basic bangle.js timer with a focus on usability. + +* Start or Pause the timer with BTN1 +* Reset the timer with BTN2 +* Exit the application with BTN3 +* Touch the right side of the screen to increase the time amount by 1 second +* Touch the left side of the scren to decrease the time amount by 1 second +* Touching and holding the screen will increase or decrease the time amount by 60 seconds at a time. + +Icons made by [Freepik](https://www.freepik.com) from [Flaticon](https://www.flaticon.com/). diff --git a/apps/countdowntimer/countdowntimer-icon.js b/apps/countdowntimer/countdowntimer-icon.js new file mode 100644 index 000000000..bf5972683 --- /dev/null +++ b/apps/countdowntimer/countdowntimer-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwgMJhvd7tEogkSC4lAC6xWUgUgNysiC6hGBL58BiMQLoYXDMJkRAAIWEC4gYJFwIABCwgXFDBAWCpoXLMYwuCigUD6czmUSmQYKC4QuD6f//8xiUzmckJJIuECwQXEDAgXGFwc/C4XykYXCmZIJCwVPCwQABCwczmgwHXYXUCwgXFGBAXC74XLGAQXELowXIVgYXF6QWF+Z3EJAhGFUganHJAoXFRooXLMAQXCLwwXHMAQXUMAQXCRwQWFC9HSiMvC40iCocxiKoEC4cTC4sRiLBDC5MiF4wXFmQXHL4/zkRHEO6H/OwwXFX5IXfd5HfC5s0C4/TC5skRwZ4LLxAXHMAxeIC4hIJLxYXEJAxGMJAgwFFw4XGGAZhD+UjLoxGEC4owDmMSIoouGJAgYBGIIXDCwYuGGAoABIQMiaIQuKDA/dCoguJJIwXHCxQYGCyIYFCyRjELZYA=")) \ No newline at end of file diff --git a/apps/countdowntimer/countdowntimer.js b/apps/countdowntimer/countdowntimer.js new file mode 100644 index 000000000..b57372864 --- /dev/null +++ b/apps/countdowntimer/countdowntimer.js @@ -0,0 +1,232 @@ +const heatshrinkDecompress = require("heatshrink").decompress; + +const playIcon = heatshrinkDecompress(atob("jEYwhC/gFwBZV3BhV3u4LLBhILCEpALCBhALDu9gBaojKHZZrVQZSbLAG4A=")); +const pauseIcon = heatshrinkDecompress(atob("jEYwhC/xGIAYoL/Bf4LfAHA=")); +const resetIcon = heatshrinkDecompress(atob("jEYwg30h3u93gAgIKHBgXuBYgIBoEEBoQWFAgQMCBYgrBE4giEBYYjGAgY+DBY4AHBZlABZQ7DLIpTFAo5ZJLYYDFTZKzLAGQA==")); +const closeIcon = heatshrinkDecompress(atob("jEYwhC/4AEDhgKEhnMAofMCIgGECAoHFCwwIDCw4YDCxAYCCxALMEZY7KKZZrKQZibKAHIA=")); + +const timerState = { + IDLE: 0, + RUNNING: 1 +}; + +let currentState = timerState.IDLE; +let remainingSeconds = 0; +let countdownInterval = null; +let increasingInterval = null; +let decreasingInterval = null; +let isDecreasingRemainingSeconds = false; +let isIncreasingRemainingSeconds = false; + +function main() { + g.clear(); + g.setFont("Vector", 40); + g.setFontAlign(0, 0); + + registerInputHandlers(); + + draw(); +} + +function registerInputHandlers() { + setWatch(onPrimaryButtonPressed, BTN1, { repeat: true }); + setWatch(onResetButtonPressed, BTN2, { repeat: true }); + setWatch(onExitButtonPressed, BTN3, { repeat: true }); + setWatch(onDecreaseRemainingSecondsPressed, BTN4, { repeat: true, edge: "rising" }); + setWatch(onIncreaseRemainingSecondsPressed, BTN5, { repeat: true, edge: "rising" }); + setWatch(onDecreaseRemainingSecondsReleased, BTN4, { repeat: true, edge: "falling" }); + setWatch(onIncreaseRemainingSecondsReleased, BTN5, { repeat: true, edge: "falling" }); +} + +function draw() { + g.clearRect(200, 0, 240, 240); + g.clearRect(0, 0, 240, 80); + + drawRemainingSecondsPanel(); + + g.drawImage(resetIcon, 216, 108); + g.drawImage(closeIcon, 216, 188); + + if (currentState == timerState.IDLE) { + g.drawImage(playIcon, 216, 28); + } else { + g.drawImage(pauseIcon, 216, 28); + } + + g.flip(); +} + +function drawRemainingSecondsPanel() { + g.clearRect(0, 100, 200, 140); + g.drawString(formatRemainingSeconds(), 105, 120); + + if (currentState == timerState.IDLE) { + drawSubtractRemainingSeconds(); + drawIncreaseRemainingSeconds(); + } else { + g.setColor(0.4, 0.4, 0.4); + drawSubtractRemainingSeconds(); + drawIncreaseRemainingSeconds(); + g.setColor(-1); + } +} + +function drawSubtractRemainingSeconds() { + if (isDecreasingRemainingSeconds) { + drawFilledCircle(22, 117, 15); + } + + g.drawString("-", 25, 120); +} + +function drawIncreaseRemainingSeconds() { + if (isIncreasingRemainingSeconds) { + drawFilledCircle(182, 117, 15); + } + + g.drawString("+", 185, 120); +} + +function drawFilledCircle(x, y, radians) { + g.setColor(0.1, 0.37, 0.87); + g.fillCircle(x, y, radians); + g.setColor(-1); +} + +function formatRemainingSeconds() { + const minutes = Math.floor(remainingSeconds / 60); + const minutesTens = Math.floor(minutes / 10); + const minutesUnits = minutes % 10; + + const seconds = remainingSeconds % 60; + const secondsTens = Math.floor(seconds / 10); + const secondsUnits = seconds % 10; + + return `${minutesTens}${minutesUnits}:${secondsTens}${secondsUnits}`; +} + +function onPrimaryButtonPressed() { + if (isIncreasingRemainingSeconds || isDecreasingRemainingSeconds) return; + + if (currentState == timerState.IDLE) { + if (remainingSeconds == 0) return; + currentState = timerState.RUNNING; + beginCountdown(); + draw(); + } else { + currentState = timerState.IDLE; + stopCountdown(); + draw(); + } +} + +function beginCountdown() { + countdownInterval = setInterval(countdown, 1000); +} + +function countdown() { + --remainingSeconds; + + if (remainingSeconds <= 0) { + remainingSeconds = 0; + stopCountdown(); + } + + drawRemainingSecondsPanel(); + + if (remainingSeconds <= 0) { + drawStopMessage(); + } +} + +function drawStopMessage() { + draw(); + Bangle.buzz(800); + g.setFont("Vector", 30); + g.setColor(1.0, 0.91, 0); + g.drawString("Time's Up!", 105, 40); + g.setColor(-1); + g.setFont("Vector", 40); +} + +function stopCountdown() { + clearInterval(countdownInterval); + countdownInterval = null; + currentState = timerState.IDLE; +} + +function onResetButtonPressed() { + currentState = timerState.IDLE; + remainingSeconds = 0; + draw(); +} + +function onExitButtonPressed() { + Bangle.showLauncher(); +} + +function onIncreaseRemainingSecondsPressed() { + if (currentState == timerState.RUNNING) return; + incremementRemainingSeconds(); + + increasingInterval = setInterval(() => { + remainingSeconds += 60; + + if (remainingSeconds >= 5999) { + remainingSeconds = 5999; + } + + drawRemainingSecondsPanel(); + }, 250); + + isIncreasingRemainingSeconds = true; + + drawRemainingSecondsPanel(); +} + +function incremementRemainingSeconds() { + if (remainingSeconds >= 5999) return; + ++remainingSeconds; +} + +function onIncreaseRemainingSecondsReleased() { + if (currentState == timerState.RUNNING) return; + clearInterval(increasingInterval); + isIncreasingRemainingSeconds = false; + drawRemainingSecondsPanel(); +} + +function onDecreaseRemainingSecondsPressed() { + if (currentState == timerState.RUNNING) return; + decreaseRemainingSeconds(); + + decreasingInterval = setInterval(() => { + remainingSeconds -= 60; + + if (remainingSeconds < 0) { + remainingSeconds = 0; + } + + drawRemainingSecondsPanel(); + }, 250); + + isDecreasingRemainingSeconds = true; + + drawRemainingSecondsPanel(); +} + +function decreaseRemainingSeconds() { + if (remainingSeconds <= 0) return; + --remainingSeconds; +} + +function onDecreaseRemainingSecondsReleased() { + if (currentState == timerState.RUNNING) return; + + clearInterval(decreasingInterval); + + isDecreasingRemainingSeconds = false; + draw(); +} + +main(); \ No newline at end of file diff --git a/apps/countdowntimer/countdowntimer.png b/apps/countdowntimer/countdowntimer.png new file mode 100644 index 0000000000000000000000000000000000000000..fe59fab3b53d0a88e032801566af76cd6a6da83a GIT binary patch literal 2663 zcmV-t3YhhYP)EX>4Tx04R}tkv&MmKpe$iQ>8^J4ptCx$WR5rf>aSltwIqhgj%6h2b1e3G-*gu zTpR`0f`cE6RRWM)^X< zu?YAB-u3sG7%QcR?1Kknfla{Lmx6mpfp z$gzMbRLG7W{11M2YZfMBZc-=?bidg4#|RME1)6o+{yw(t<_X|`2ClTWzuEw1K1r{) zwa5|Bw+&oew>4!CxZD8-pLE%f9m!8qC=`JAGy0}1(0>c`thv3l_Hp_Eq^Yaq4RCM> zj20<--Q(TC&ffk#)9UXBol0`Jkj~-@00006VoOIv0RI600RN!9r;`8x010qNS#tmY z4c7nw4c7reD4Tcy000McNliru@`QG0lh#>W? zEdD?*Ns9@&_pa6M7|P-X*v2eN%^xDQCygWkjVLS_Dm;g@04a~;o)HD$a;uxYveGXr z>Yz(u9*0VBB{~syN#9Csag~jKxoF zs}@agLRy^W?Vm?f6(*Vbdm+$Jf1l z!LyP;%0)_NiUKtXgwOy^Yz4>}fE{C$eU$xP&B-wX5LdSDX+qfB0E_^@7^?*nSN87Q z+zbHSrH_x-XoamBK`0glq6zdL9{|2|2_V}Qm*;Pj4xZ?X7=XC)b`9lP7 zml_#SpUK|)$!DViknrsDW>rz@ZpZ84v<=s>RO1ReY=sE`06YZPV6s%d849yF^g&VN z6$C`;3D+86u(pqw z4;iqfdFlKd)6AOnWE0eo0RSZ4m*Hd5jC@H6d|c77uzsT)`n>6g(MizVdGGw(iVJO> z0Dz7!C7>-o?~8AuyKiDb-BD!J9fjx#VDf}iTsvDR0@Z6n&%}gO4Sn2=*1*D3ine8| z;C%UyNSgiyTNwL*o)NrYFH5tW>ZxihDOa`+TUi_Y9x z=ua7sq^2{Vio)~KqIJ0$|J%}d{c31ow4y>=X!jgCEPY-ia!zI-!-Rn~8xR|<4ap;S zw1nowu^p`_*!d=OeRkfmRRfPX!}6&ucrjO5>Hd(mjOPjOOi72U;>D1K533X(HxZvb z^8&oODBg0a8`@Vxszz;P3zkKRbdv9TRjWboPhUc`RvfGP4+BZ#aCX^hFhV(|!hYEF zt@-Al0CZINJdMK()uOL+4_i>lFGd7lD_t;6BMF(lOuaeNkd!+m zY+(-8U&6_A4N#dH)_2YGOE8$2%3E6ARQlEAfB+;deU%qe`o6gmG|Uuys-+!2*lNMv zL;pqnh09@mtBN9;3m5a2Btd514hTS`q=@IZiD@ZepZ?7uB}A_y>~aF_`Cox2%D_nu zSjq)pD=UeWL~8V_^&ek?Flx7m5u*Y+%(Hoc|IwzB60IKqO68{r$9ZYaWIQagWtn-e zqa=O5*$)6=Y#xt0CO+<=0kBWV3RGfD<^UkszKrhpL}*3&&;WR1;vj4FJP42YSEB?m ze%(b(5*Doe9RMINBNgxdYz1O;;b-BtjxKz9<^lvtF*V18D7`KquiN9n)?F6d?Cb^r zn4*lB;&%G@F${hH2!UT;>yoqpZhw5f&5DNhE_^vVBWwT-S6a|;rRDaxC37NHl|C6b zdUbYxAv^%M1&J4lbbbIBV=iC5c&`gHCXNFDA>+N15*5=>*Fv13S8tCz5%(mUYhp+u|RQ5Y{d@}ZJD91bXt@pB!C}L_(=E$Q$ zO0aZM(H*~3G2u5yctv!t9{`o15x|mRiOt!MKCg@@X>4s_kHj=As|r)!XYwwAZl&t%V* zpgpm1XH~t^t9;D+L;9ANVefH_ned6t7h(Qj2Y*n<$SYa-V`)qZ3h{}%|a`6n14M44@RueLGhXmKdLasF!a z&+{_%8bK)ZSEq`&Q?=;7(T@J?Tj?zb@R z;zxlV91;`qc<@oy}F@@Bv+shZe6(fm14#uns672bN z;mV$j({73bP3^FE*-&KEAzyL8U~NO(jcXvmGrNZotjgY7y)zhN$m0fkS#d>_M%*kA z64ur1C~j!l7_dCsQe7PibI1*^@t=n)-7YoH<&|5