From fc6ecaccce783eb5bf6d3571b885bdfcf78912be Mon Sep 17 00:00:00 2001 From: James G Date: Fri, 26 Nov 2021 12:35:35 -0500 Subject: [PATCH 1/4] Add new Interval Timer app. --- apps.json | 15 ++ apps/intervalTimer/ChangeLog | 1 + apps/intervalTimer/README.md | 34 +++ apps/intervalTimer/app-icon.js | 1 + apps/intervalTimer/app.png | Bin 0 -> 1823 bytes apps/intervalTimer/images/done.png | Bin 0 -> 2356 bytes apps/intervalTimer/images/pause.png | Bin 0 -> 1231 bytes apps/intervalTimer/images/set-active.png | Bin 0 -> 2226 bytes apps/intervalTimer/images/set-rest.png | Bin 0 -> 2364 bytes apps/intervalTimer/images/set-sets.png | Bin 0 -> 2212 bytes apps/intervalTimer/images/timer1.png | Bin 0 -> 1717 bytes apps/intervalTimer/images/timer2.png | Bin 0 -> 1646 bytes apps/intervalTimer/intervalTimer.app.js | 306 +++++++++++++++++++++++ 13 files changed, 357 insertions(+) create mode 100644 apps/intervalTimer/ChangeLog create mode 100644 apps/intervalTimer/README.md create mode 100644 apps/intervalTimer/app-icon.js create mode 100644 apps/intervalTimer/app.png create mode 100644 apps/intervalTimer/images/done.png create mode 100644 apps/intervalTimer/images/pause.png create mode 100644 apps/intervalTimer/images/set-active.png create mode 100644 apps/intervalTimer/images/set-rest.png create mode 100644 apps/intervalTimer/images/set-sets.png create mode 100644 apps/intervalTimer/images/timer1.png create mode 100644 apps/intervalTimer/images/timer2.png create mode 100644 apps/intervalTimer/intervalTimer.app.js diff --git a/apps.json b/apps.json index a7a74f4cb..a0bd5bfd0 100644 --- a/apps.json +++ b/apps.json @@ -4456,5 +4456,20 @@ "storage": [ {"name":"timecal.app.js","url":"timecal.app.js"} ] + }, + { + "id":"intervalTimer", + "name":"Interval Timer", + "shortName":"Interval Timer", + "icon": "app.png", + "version":"0.01", + "description": "Interval Timer for workouts, HIIT, or whatever else.", + "tags": "timer, interval, hiit, workout", + "readme":"README.md", + "supports":["BANGLEJS2"], + "storage": [ + {"name":"intervalTimer.app.js","url":"app.js"}, + {"name":"intervalTimer.img","url":"app-icon.js","evaluate":true} + ] } ] diff --git a/apps/intervalTimer/ChangeLog b/apps/intervalTimer/ChangeLog new file mode 100644 index 000000000..d62860265 --- /dev/null +++ b/apps/intervalTimer/ChangeLog @@ -0,0 +1 @@ +0.01: First Release \ No newline at end of file diff --git a/apps/intervalTimer/README.md b/apps/intervalTimer/README.md new file mode 100644 index 000000000..f56dd74d2 --- /dev/null +++ b/apps/intervalTimer/README.md @@ -0,0 +1,34 @@ +# Interval Timer + +An interval timer for workouts and whatever else! + +## Usage + +First set the active time (i.e. the number of seconds to perform exercises). + +![Set Active Time](images\set-active.png) + +Next set the rest time (i.e. number of seconds to rest between exercises). + +![Set Rest Time](images\set-rest.png) + +Finally choose the number of sets to perform. + +![Set Number Sets](images\set-sets.png) + +Active time will be shown in red, rest time in green. The watch will buzz whenever active or rest time gets to 0. + +![Timer (active)](images\timer1.png) +![Timer (rest)](images\timer2.png) + +You can press the physical button during timer countdown to pause the timer. + +![Paused](images\pause.png) + +View after all sets are completed. Press menu to change settings or restart to start timer again with the same settings. + +![Completed view](images\done.png) + +## Creator + +James Gough diff --git a/apps/intervalTimer/app-icon.js b/apps/intervalTimer/app-icon.js new file mode 100644 index 000000000..1ca594050 --- /dev/null +++ b/apps/intervalTimer/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwg96hWq1WgDCgXWxGZzOICqQABC4QABCyIXFDBsICIeJyfznAFBwAWPC4Of///mYYMCwgXBl4XB/4xCFxwABn4XCDAQwICw2ICwf/+YwJxGDHoQXHGARGIn/4C5QwBJAwQDC5QLCIw6GEC5BIGIwQLBJAgXGJAwXEJAgXPHgoXIEYIXFLwRIFC484C4h2DJAoIFPA+Ix4MGAAJoDHYgXKf4QXUJAYJGC5p5CF6hIBO44XNABIXGEw4AIU4rXFC5jvFc5AAHxAXGQwwAHQAIXcPCB2FC4RgOB4IXFJBxGHJB5GHJAYwKFwIXIJAIwKFwJGHGAYYICwIuIGAeImYWFmYJBFxIYEwZjC+YtCCxZJDAA4WMDBIWODIwVRAH4AXA==")) \ No newline at end of file diff --git a/apps/intervalTimer/app.png b/apps/intervalTimer/app.png new file mode 100644 index 0000000000000000000000000000000000000000..782c449b3f8940d4fda51449cb0a1b40198116cc GIT binary patch literal 1823 zcmV+)2jKXLP)T;~zTf8RNKR?_ZDvUhc{Bwyk**2W~b2)Ry8<9i5= zNz?Sf80wZbZ64xUA$bXTXhUfzg}#)gjSL}>rvwsQs10^0rB!4U6EIRJZi_9+cI{Zv zbysU=Z`#|LK1fGgX=WxUADjEW2!90fG*Svgvh#&YQ35|%e6W4zcGCHD6En#Sx8o_UMUzC*h2A4U zP<=!G)(_XkfZky-T#bR#z>9?kh~0*?FuC^zh6(+1dob#=@xl}sizOMFk8>-Y$~QxJ zCmv~ed1SXr6&|^219~SXUGA{)CxK_G;kOWcWs=7|PWsL~T9Rihn&kX!lwc~8Oa4o& zF?DRDvolsnM#V7NJ1oX(lm}=y?55|rlD-c>x7$hIwhioRtji@Ib%l*{kNrn%?^iA= z8sKUSoL-Ic0CfjEeEn#70|1CHQ|WQmFG@^I(=|-vZWM%Ndr<^;x|AGfY;FZZkuO$?MK_aT%QVab1p*0w2eV) z!uQ%ec#Y+(=QVNssuZuS0SCu}o0pOl0N-hIV`y2&X>#hkzH1X-gccaS6=L?wg&L{8 z2&blawk>-f1oh&RH|Dq6@!A?-N~Vvc4EwOlpxa#>48GOw;oF;=Nv2Ikrz8Ap;vTUY zx|QGUWLtw_O`W9EC++x(4G_^p)Cp_)`QLSA{io%SUmcVj6&yLFcva}hF98@Jl$ z&C1qLKRhM{)f6@c9JoIJ1h5&vf-o6c;ImsHLb0k6X<7JP zPCUA{bT(bnW5M2v2AF2%(DDIpCt8J=xu@05^AByzqb;ON{ylMz(Wx-eqME0AXo@`d zRdBe7r;wmvw>93L^}(_@xwDn6p5iw(8&2@T#sBipV8x1{B(}SOxE(gN=^r3;^&q*Ykqk zKHnrV!e8&)tNN^5Y%p?Fl#ar6I|G(8mQm>f6yU_ye0;ObZM&9UWn`+)*P*d+y`~@a znu1^Sbh62ne|L1Hc&e+ZmZGvUZD!l;Z{Pi<#BULUAV6^Z{!;8cnhe)pFIy2#iOw z2Iz``LY^W6ETq)o8ho<)fNm#rGW6`hvEnJNzbMIgxjn;3+XKTRV4&MaAd)EB? zY?S0zco`C=aA7u@Ly>ns^|yRs$6GQJr!&r<0|9_wD#M>=BBfYs3IWc}Lz^9Kj&jT-8^DE&518XRYtHs{~F|LFY%X1M`D)X;@mE5uOt1A$<|i~52xpw+44H8h;sqK76;lTgZJCYk1DEX8;Q3MekzwK)T3&Uq^rmlo}J0VO=qBvD-INi{Gpd@Bshs_#Xuib55gPS>yl! N002ovPDHLkV1m2lg2(^> literal 0 HcmV?d00001 diff --git a/apps/intervalTimer/images/done.png b/apps/intervalTimer/images/done.png new file mode 100644 index 0000000000000000000000000000000000000000..d210540d16cbee6a672052c93bad3179cd6926ba GIT binary patch literal 2356 zcmZ{mdr;Ep8pmHiyx@8%F)w+eG*j?aSuCZM+8SV1n4+*Enq`W$n5GcALPt06m6}=YtBq_X7-QwednF$op~Jvy;3d7tNY%5?g>zBBZO_va3}Q5F2%bp?iW}fYwfnaIFP@+Vk7vZ-$0q$ z)gbA6zrZoUsLDx6=gQBiH!QE{=pxvjK4nQ}s40yQAaV;RC6q!uz9E0N5#0(0s8NLQ z0&uhYwe1NQTfa1?R|6tuR!}y4Z@3O>e|?5axL@aD7J1tjQ{htpWJLeRSw|t2svSa! zJGtPR&NfRcBdINbXhQrMBGL`i#xe+sY@F;Y1;ms4^5;r5eriNSPPB}>fnuuQvUa@x z`i8`hm=2caFiYPN_RO`)&o67E5P(aR8+!uLjxZA!L@)F*tv6i_n%{HSH%bqpvVtd? zH!ef>3~$hW0Ee&M`oKVXfm@%r!bEb;aV?xpOMM9dWRz2*7!Df5E?(Xgz_&^^45GmR z{Ew$$>RuziF563FgA%khCTtu(>5#!ZtGVV=0Q{ zhaQ#Rcszu&$o7PR)nYRX-V5Vsk%3%_D~)+SG0o{$)C~u96)D?C{77c{2&D zOe_pk$DaJrDZk5MWE0G6#!*_G^a6yz0`z_{O^@!hM9DFVNk4z{K^zpmzqaLB<_p>A zCh)bpdyMOmJ2gJ!u?VONCFmOdr3l@IU76y{QS(;4N|U16ZHVJE%l zum0)EjQI~eK(@Iuu>-7Np$bJrZ+4;7T`1~CwWQ6HYF6W3!m5mznN8WwsmL!jmd zHFfly|JUaoD4@y=t~B90pbe*WrRQ05v8n{cr4g4Y{2i;79#=(UdQpGEqB!wmU3N`f z$ACx=Ec_$)4q`w{?#B^YpPfLSyV?}yIr?&m2OrNoJqo=G9iHVmV8G&+v^oZ!F;HU= zPc9S#o?M8i`#mP1<18SPHBK){2vsUmtY5S5zPni8J4^4}9pTCvDV}$kslTJ$U<(6;?(@4R6W)tOg4>gXE9{7n>mctPH@`-+2pMPKap53B(UWZP{6M=)8G;Px z_VHSrqpdQy{B8){>oQ;b?9c`3g@e(Jr3mtpkXAGM3Ku74Tvg6Jv+c!f{gyA!w8xSD znx=r>c65(8LDT4Eva^B&xW_r2(st2vy`#URYDcb{+m!?S(~-+qc^YDGR6bB4)6W~A6<#ZFpGlGZR9DdQv`i45VJzp5NxuortKnc5RXuu?5o?i0<{A;xr+lYU|4M$k~ z>!yS+5ec8(m#aL|B|nHtZ-Xi9B15vNN{E2 zes3m6R<=(MI{Jma&h$0Qd>G;QgNz2#gSw2V#$o1*z2&$cxq#8NVT(`+#~MJ|u@y-}dn_UW`p+r-Ws zcw%V|3?H>D8VRsnZ`@g8MJ~y>-1_cKFY~Aiqa=*H8@@#22T* z?`Y%f)|E^riV9ng^IUJerCR&F%;4gbGUyPh>hp(EEn=VJk7JO4gV~;+7AQEvuNZlg zT(wr;K=m>A8rLhl)BcTc{8g@pF7Rr-uvA#tC~|~6i_%6*Iw?f1ivO^<8*`Gy>T#W e?{H<%3ar(lH}9wIm9h5rH_883YR literal 0 HcmV?d00001 diff --git a/apps/intervalTimer/images/pause.png b/apps/intervalTimer/images/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..727380799f7b7cd5b038c4be41169cf7408bdbfb GIT binary patch literal 1231 zcmeAS@N?(olHy`uVBq!ia0vp^8$g(Y4M?uv{v-}aF%}28J29*~C-ahlfu+;a#WAEJ z?(N-+dBM>**B@k{;>|1-tAHGoNv=Vr;nlRZ=d2Z9t9s7kB?{ncl}Q^^5-ZzAv12 zNLx;bLE^!e*-QxyjDBFZic2IkTn77=l}+LS*ptPLjBFNQzr~Cy1I0Rl03kW*f7k!G z{r1~q^Y6cFPq?jL%lIMN^6%&MOh4wYe{r4Bo~zpI+b-`XOxszQ|2#MUvdjFP?XHh6 zl|SFSKL22S&%@RG|FiE8e{Q+=-{aR8t?uuecQgILdbV#@@Be4{Bmi8S1{BpTF!#r*_N*GudfREYx&`d)08oDPVx~qngUi6 z3jk1XcA|PnvGPA5yGfcWp1!9`0dc{DwjY%92r~f420K&t9c9z!xdV5mtZ-=2hW$NC z|5<~~d8&u$ujxmd=5n6jDU3F0x9GR^s~DYaL!on2*>+syeEi$Nzhs2oZ8nY@@U{uX z+_Wyu(_n$>%_#E}`hNA>hl4qfBjqS+0)_g2H(%a9ju7@N>?!V*5ql}Qku;UVzo{U8eB6{Ss6ql9sYDG3 zhnCaVl;QlZ=dl*0I^V`oYima0_4^fL9j)3yJl?AmzV9rW0la)Y!P@nMcXm>mTe>~D6f`R9wS{jNc9s!GqYx*$TrVzA%!Wxn<>0nyIHPJ@(dJySXN+QIV;}=8%tR-b zzTKZySrxchD&T?-2IYol-H#nkV4*Ccg+|BkcQ(ri)TC0DsV&}xuyXO4a&rezQTOZZ z?pP3(Ro%(W1K@D_?~ZxWevAT=Z5$Ec!S-LSQ;h-a-lM`wk;=~TANXXc?DDhp7gW)J zo$}gLr4Rs`u`Ayg3&g6w`{=nKK;)6-Plxk)fAvff!^3V35|B`DhJ^c2a=&F!!(C^R zl!%Z^EJBLq*dQJM>p#xVaPFZb=okk8@{jJdzBI9E{`l zZOL)`mASX&fTD=1sSX$kjLkytmFKMPeWc+fk^z*>Gr8#9(V*&QoN}cL`GpvM*RAOE zK7glY!0Gjf{BM&psV}y2D}JokDx za#B_)%u-p~SC-W+Di^OeSsOd7o@rmv#+ti=xsaS?met5?6f&lkIM8yB&D^D_1kuzi zUt<_oy?Y)RKu@{sP=%5M6;u2u`A0)XC^%@?qXdJjJW=|E18mDhd)kem=E3eIH-1oW z;7WDi^!$hDkJ~lNDB*U1R=S!>L5jNhlP*k!$|a4YGR7di;Q&U95{DMPQ#|t-2EokH ze6bcWx;fY8!qRXfY9kaSk!X7qO-!VzNp5eK<2x!TKoN{CMI0QCS&q+E{9|BT?8euE zI3HtgByu~_<1?j@RmS`b>R_uoIC6#^J7qD|2T~UBMskPv~8_7!; zyZ*1{OS7B8ESta_t`dKwqaiCd;Vy!FQdUEdE6)$x5(vJHDoS1*Vpv0g?XH+Rq&*1J z#G2IZNUX&+I=FKQ$?(bVlik^LZ?9pNYs%~cpX;nC)6eo}Y9fSBgty5AuxEiod@GqD zJKr3z1i2jNe8XuNF%4^qcAwb=V)UB?#5b#_``HA_HA-b|?@y!Jjik>_vuYGLliaCs zkqYBrOsUJ`)*_xcz2`uWf5c@OHr)cjR%R&a>Vd+t&LG8m-)W;s_mtpX1P`~^mk`1> z)&!M?RX*afVzMmkHh&lMFSlc& zy~Id!t40%@m<H@_<8IxHA6&#fK{>;~Oq~~&5FbOi>&oLI0lP_#h z_xGQ?>nWOWc&*i7#vya41mPWuXQsQ;ZGThQTf4h^j8V)c|@ z^IInnz%4}kr4qt+hxTG;>W=OhaE&u0-Ad$*_8zfy zlZOd_OXhVi{okd{$ZUtT7+ZQp*Snul%^Mvk^o#$_gY^Q~e%w}b9D9(%Mw@}FxzCW= fNhs}cNqgLli@fNNnkp^n69Swa-KgdJ8CU)dXes>m literal 0 HcmV?d00001 diff --git a/apps/intervalTimer/images/set-rest.png b/apps/intervalTimer/images/set-rest.png new file mode 100644 index 0000000000000000000000000000000000000000..e33c9eb0225efb199d0f0e41c0327ebc794e6549 GIT binary patch literal 2364 zcmb_ec{tR27yr&oV>H$SY-?1aYXMp3qIgR;GP|9}5_-#^azJfA<#InQ&R^Lak!`f(>)8T2+Z06@mx z&dPZMdA~wZVk1}7exz;yEX>)K0LnYmCIOIKu(vwm!k|v)z6<|?leE6GzW!Nw?`eJc zwykNM*TP2|47Blqr^*<0>nkfOBTGcsZsbhFZsOK`d$9lRSeYj|h1rn4v2(BVJwX#KZ7@^oY$; z{{yMJK%bp8Ej!y79P8FvHVJ4P`t$j!IAe~tO=PeSIINJaNOM63B9oP7AGR0QaWyk; zp+wH(cb8#2=i)Y>G0@?fqh?p{p!3dN?DWDB)7@z7FL$@sC@ALz{+tFUFMcE@oC9BC zfa>oi4a?IL;lxHa4@18p!Gu#ESW!JTi&)@k$kKx30+G~h`PsD>EdtI|c4()NYCYFU ztC8lP! zQeXzGA~C6w?84$3nRhJ+w4-RCMS@z&tDjb2fSeP>H3fEUj>BwM*;zqfUO|939b|t0 zHl#7L!zoHHQ^5~|Wd<4EbRAu>{#IxnGGyw&QE`5)@Ny82R}BYE7k`FmFnwr|$OOyi*e0vz^W!nE&$2+N(r5I%sxYzrd~i`&a$YV` zw-fn6u?eWbv+Ls+tyNF5$f-4BE4Ik~12$t?9sLtD0GQ=nWKvIw((=tnE8`_J8S zSnk0DC@PL&!sLn=?eyGrv}EvT*<9pJ6zyvAt~mz5*|=3HuPC&T8cak9@kQ0Wh%YR#QIdm+q$c;z9R@+o*LMBTQs2p6R_W>Uu?6J-zq;bj(T_<* z?9>wgFTh&}<7*V1m19_N4y&|QIk+|v_Zr@ZGgCmUWA*OSC8oj}{`SZ{1?M0qP_}8Q zln_Y_4}Ud$5SVJ5sfyJm{`__#mAnslBW#i3c+F<5NANFq;Lv4mr8aEvh=8C7ymY-@ z>%HqfXwD;x+%?ux1`B)dcTJ`fScD0vf}Lxu4nc6h^URIAx3 zStvErMDpiulE$YB;UvpC9ai`B5Du&>_o*6FBY03606_Op2F?=Gxnuk6+9(m^?# zYI(!eUjK1(S*E&DkW5126%CI22;z37rnt?8_P&cO6l4vn9wJ47=!d@gerq`;-K5de z(f(s{AYYJiS!jfbp2|=61plNQGqe(}`F#?X{UNOJ(wiGo0-5X==ycS}ev{Wb0$Sa- zK=s0bA;lgONq+aJ=U+8HFu@Tth3vN&#pWRH8cx2HA(yX5q6% zq)4u1C!#&~2K<*h6r#fI$69RuBfhOnPj9uq5*~cxpxWO{(5%r3$&cqMUZtIGu6m^= zYm+$P8(&M7#k|yd>Z+s6WcbDSq8P<^*N-MMW+nn+*#3PGG5*5Gx6gV7@^Wt!L8GWo zC<$T*u*~7APsRv<;7Qp%x(RR~;uLB5y6z1kkcO10rO)9Z_o54PiQgdmc9+Qh3~^>mwLAr>J8dEj;ObGh^! z(Z)udj}w}Qpqnl-AFny0j@px)kirM>sFMO1uY}H#N_kZpiZh>!KW@u5;6lz7Wq);r zdGw+K`xaimJ3pj4)Ms0>Gwz~8re5u7iva@QMJG}CNRj)2s5N_z3?GB%8@-8&WPe}R zvdKzr(e91cscHz#lG=0E&{J~r&dapT+1|r2Mz7wrOJahl@G{dcMqjjduvx MTRT~m6KHY&1|~)^i2wiq literal 0 HcmV?d00001 diff --git a/apps/intervalTimer/images/set-sets.png b/apps/intervalTimer/images/set-sets.png new file mode 100644 index 0000000000000000000000000000000000000000..3d5a9107f8b6fa7ef3242f7863b63b8531e71177 GIT binary patch literal 2212 zcmbuBdpy(oAICr6t+`B0YUR4_XAaG!8@VTv{LYBYZJAM`!$NY*7HwrE6%|rKlw8tK zE?Xhr9}{P#Rc=egoLrKzkr2|)`TO^K{QfzAyx*_KcC4?02hDR0ozAHaLqVkNkAREUVZd(`+j*4&aOhp3|lbm#pT6@!AX8 z>`WECn`3Jj{BQCNN>WbIgQPrkBxDZCJa!w3w<;!<;oj#Dl29~kar&?-?0SXls>UYg z5VP?Bzsq|o0eDAS9nS+foxYjXz_(?zFdh-*d4&8H@jnFXD-Dek8N*8p;Sgz6HCCe4#I!wDX3LzJlwl3@Ah`7u z%X%!ajx1L;;hGpbsb-*j>5H|MghT?deePu9t&(-x^7&Lz|)J*&77`^uQ=W2A1>PU3^5pPo>+xb-fUzG2Z z$+TKc9^O%x&C3&gxkW&-62f|4a3SiOq{|ahQkd3tZP@?uEp-~FT17 z&x?;&t&moC|Gq`(9|-9Ztz@~lV(|>a>VE3t(cXQWQq4wbLV4Z%;bffas(o&pUp3`Y z6piq#=;*@yujxUpOk1@nyd9Qtvoo6m`F6~%@#}CrRr`jy&8wo>4+D?I=Im&_g^>Tk z7CGw!@!mwEdX%t~MFTjDLW>cniHuTC%cQ7)3E)9kfo0?iDqaH{k0StQXadBVJqu-< z=-~z2unxIGCQI}ALE>Z4XHHnrrGq4vd`fLXpN2*UC08(K!Z>6uph6Kp{V~!wdGyHz~3!g_(l z7qAj;xRtGoVOv8VUew62f{{MD*tcQPdSA|K6DK(;RC%t{2cvlCJ}pt!xb9cCZd0#X z8B+G$P={gP9AAP!M#(PoH(YjJu=Rg3pV-)J8=3ltQCLFLu?8w`e*uC*Px6}QH+K%8 zq-&XHV_Zl_I^HMuXdXrlI2FR|LzQ`wm z9wWMX$!Bpcvy}oU6^$`BaF)@S2nd1$QUVBVZ^vJeu!5qfYGo4+pLlgj(5<>UK)k~a z>zj{2DqbISLurV{62l)G6_QsG6uh|_^x>tS2ZlZdALYS^=>1^{y?VV6V`ME*tJdrb zP#JqztgO-C^HlA(khr0-ewY4S&j2A5rBY8l2MO*LQf}V6BXk~#Z*?)Qzp%w$g|oKl zsrFZD1pSjJMFWn+{;^KiU&X!jpw)SFjsSrVnep*oK8CDeeKw@cZZ&kke0Zv6{yZzj zx!s>bArl{AJ{UD&hmneJ{>dXLxBK$SK~d-x{Q0;iE}`Y{ZT?%$JNi^GL)y@F@HE7L zB&v!u56+~|deJAcfd;jJ8&&x4t6cOp`Xpc!e09}Ohg~m|enYa!x$f630N&hlmpbr{ zwR7zQIl=>7JArT4_bu_rD6P%p4nQN1q!0dIVQA+KhsCFX^VROfB&EMnp15-vaaHyp x@Y;>^@_4kc#exjx3e673`u*KOv0E#_bt+D-ekLb;=?=$oZwn_j+p5F;B zxi0xVC2Q7P-GX+J*r#PFq2BMU7SCE8_G4ztsYCC z{C&N+zVW}lj@I?RynkOkkKR!^-@BIe-^*n?s}6?S-@nbV=WF(-Q>^hnbDDO{GcWk^ z_uVN~ASYk3K;`{o>A#)-t)KP@1uedK)2Jqh|5KF7f9nrkhJh#7=@*9Eh968%-F86x zQ`}EBw+FsgpL4CLv05MTMfCiVlHG>Q2U-oHw>dqC->6j3UD`U^jcI+|S*;$kL~WLN z7Y>EBdBk0xe#z+>M-0d28f_N7iAn_>FP5;Ln9bCGK+{KE$LWDc35#E%RbrsZhuQo0 z*h)J-5Wd4BFM0Cx>D%@#95S~`4l%L#IlDhFS=B72^j;`~CGJq^fh3l=rk(@dJNP1G zIM1BEJzYrP2ZQ?M{*EV4pT3p$V)46OdccV#uC3?5=@YZqCWJF}9}wEsrpPjFfzpPS zwTT)+Gp28sU#MKr+-q$V#&SoO z2eCi6+LRkBD}Rd`F^OAf2_7u_M&=-sUbDBCoaTAH6M_S z;h3|qohj$x$#?&|Ty4*b-Fx+SR#wjK zvOm0Q#HNVyG~T{rmGbx_lfC8|F3G!d*4v-23)u9!ZvL6Ik;{NdU9AJ;w z`GG^aakF_;iL&kY!2AbS?{jd+Zqd2>yD^(HbcZIB{ym_L8Sw|h9<%o4O}IYa{q<(^ zou|yI>b`uw`rPfet9^X!y)9okbnYE^#lA3VMaKRY&o8&coHdS1_!?gJCD!7X_EGH< z&#OxBUoQ^%|I_w&_^eRJW$WD^Om9;X6sVYX$&BgzA-7qYECLl?!cQh}C~RoyT{zNs a{}>blt8~kL2+ITOAqG!ZKbLh*2~7Zu?)FUp literal 0 HcmV?d00001 diff --git a/apps/intervalTimer/images/timer2.png b/apps/intervalTimer/images/timer2.png new file mode 100644 index 0000000000000000000000000000000000000000..026774ba27290db5b8d9069c441369e4ebcc8ac6 GIT binary patch literal 1646 zcmd5-`&Uv29LLL@UeXk#*~&L++UzRZJTVoOocPEGKDNv#vY9nwDo&lCDBV)SEIq4^ zl9+XH>S>leEHMXo%O;if(lRv^3e!C0M9rxabhN*sA3opLIp5Fs`#I-(&bKT!CT#7R zjcYI%%-V?Xka(lN`Vo++(O!{`v5d|nJ3cHJ)AGn}5`!`IhzQyCJ(o2#GLm8IZ$W>x zXmA`h+kB|@PWac>^I-=Rtk188f5pDC&tjQWIWf1S*I6MF&;j(SslB#}cOnzE6P-Ad zix!Mz%QKs3n!cG0b*P<3^kK9?`wbQGjjh2Tk;;QyAp3%k2~b_}SO<>N(g4uQ{`@Ok zFVY7>yZr*Yh$3tQ4&R=`FLfuIeaeK+3Z+sz`)p3j<8>oTAf(6k+hnPG%BXw$&ih#} zn)?y5%4CVE7wO>2v1N;o@qR$S=U>8C-zx}F$Wi~XLi(g(hJP^=*2VCG>Rrf4ll34> zE^F#uXc|hV=x{t-lqL<#2Q!wQ2mPtO;rOAN((%TW<;G;ItIS?k7f_~@E;=g@7s+qj z8gcZ=40oO7?OlHhsdmw2qwn!ZC&Vw^?K(Q=N)Vw1QOq231Sbo>9FT5g4QPZrN>GsX z`#@bAxJl>GZ!;2{40y-08BBo4txPM=a3&+`FWzi|jXla6bg3#v!>DNPbYoAh`YKOk z>TP&&jW8k*eo5NdECcK2PN?EF1F*_7sZu7FPuw*uci`Kd`>Uc=p5BNpO0m0j84X~z zBPnmgdyWzg@#{%|qlFmN>Wtba;izQ5iYS!j*(*L|Vu8xjGJ|R0trFv!S-@(}p!_6` z>TrIo{xL=)YZLCha9! zPBsD^HWr3aCQY4zogO>^=kXigB?z;WneLo-l+3tW_x!z58D_vLtvT`a4qm$2fi4Iv zh(wrDPUTNy=iE~n?!dy6nw+-0Rz}A^iEaNY;U1VBI~Ot6Eocy;*>u0>QvD{(z z{zIHfSJJiRJy=JdT@943Uo4SKBovQ+A$%Em$v{QaJ0Gq)+df4KWmqrT{^CL+QvOI0 z*dyMed0~{Q$Rx}YqHd2h!~tO7arK*e@KelI%2#K&`X%+;5_O}nXBona(86w4|2?6a z7p43O3Oi-T2&&FX`fKyqPDjv7f#9g@5;)(dUVJS#WiL)=UpKHay;BnOIFEa9fw@k5 zy={`h@wu?$HYDr444>>b*Grywjy)ge3*__L(gLLHlu$<${x!Y57(F*_JjUA(Dm))R zs*a~ETl<WK)-N79D(fuDRpg!y8)A(J z=JTiJiG~)|wA}k84=|%}K5P@g&wl7^e$k2>@@M2D^_|zRjGFH)+&*JDn;SU1V3-gY zW(wXl`N)s#4`OJf#VsLD9Iu8RsMcJZb{+4;sdDWlkZ2nGR(cYI|2EQk93nVzAhBc% z2-UjbvWtzy;^;UV0DN?+*f$u2?Cvyrn416xBktHa1EA%;gfk@=q}6p_1>OWWc6IZE z;KOLrDRP()gM2r*F4dW)*%Bdg2|0{9|9t$D8n=R-N$`TV>UZ@T9|$Ib9uv|MoP6Xz D*O<~f literal 0 HcmV?d00001 diff --git a/apps/intervalTimer/intervalTimer.app.js b/apps/intervalTimer/intervalTimer.app.js new file mode 100644 index 000000000..fd57dbe2b --- /dev/null +++ b/apps/intervalTimer/intervalTimer.app.js @@ -0,0 +1,306 @@ +/** + +Interval Timer + +An app for the Bangle.js watch + +*/ + +var Layout = require("Layout"); + +// Globals +var timerMode; // 'active' || 'rest' +var numSets = 1; +var activeTime = 20; +var restTime = 10; +var counter; +var setsRemaining; +var counterInterval; +var outOfTimeTimeout; +var timerIsPaused; +var timerLayout; + +/** Called to initialize the timer layout */ +function initTimerLayout() { + timerLayout = new Layout( { + type:"v", c: [ + {type:"txt", font:"40%", pad: 10, label:"00:00", id:"time" }, + {type:"txt", font:"6x8:2", label:"0", id:"set" } + ] + }, {btns: [ + {label: "Stop", cb: l => { + if (timerIsPaused){ + timerIsPaused = false; + resumeTimer(); + } + else{ + timerIsPaused = true; + pauseTimer(); + } + } + } + ] + }); +} + +/** Pauses the timer by clearing the counterInterval */ +function pauseTimer() { + if (counterInterval){ + clearTimeout(counterInterval); + counterInterval = undefined; + } + // update layout to display "Paused" + timerLayout.clear(timerLayout.time); + timerLayout.time.label = "||"; + timerLayout.clear(timerLayout.set); + timerLayout.set.label = "Paused"; + timerLayout.render(); +} + +/** Reumes the timer by setting the counterInterval again */ +function resumeTimer() { + if (!counterInterval){ + counterInterval = setInterval(countDown, 1000); + } + // display the timer values again. + timerLayout.clear(timerLayout.time); + timerLayout.time.label = counter; + timerLayout.clear(timerLayout.set); + timerLayout.set.label = `Sets: ${setsRemaining}`; + timerLayout.render(); +} + +/** Display 'Done' view, called when all sets are completed */ +function outOfTime() { + var stopLayout = new Layout( { + type:"v", c: [ + {type:"txt", font:"30%", label:"Done!", id:"time" }, + ] + }, {btns: [ + // menu button allows user to modify times and sets + {label:"Menu", cb: l=> { + if (outOfTimeTimeout){ + clearTimeout(outOfTimeTimeout); + outOfTimeTimeout = undefined; + } + //stopLayout.remove(); + setup(); + } + }, + // restart button runs timer again with the same settings + {label:"Restart", cb: l=> { + if (outOfTimeTimeout){ + clearTimeout(outOfTimeTimeout); + outOfTimeTimeout = undefined; + } + //stopLayout.remove(); + timerMode = 'active'; + startTimer(); + } + } + ]}); + + if (counterInterval) return; + setsRemaining = numSets; + g.clear(); + stopLayout.render(); + Bangle.buzz(500); + Bangle.beep(200, 4000) + .then(() => new Promise(resolve => setTimeout(resolve,200))) + .then(() => Bangle.beep(200, 3000)); +} + +/** Function called by the counterInterval at each second. + Updates the timer display values. +*/ +function countDown() { + // Out of time + if (counter<=0) { + if(timerMode === 'active'){ + timerMode = 'rest'; + startTimer(); + return; + } + else{ + --setsRemaining; + if (setsRemaining === 0){ + clearInterval(counterInterval); + counterInterval = undefined; + //setWatch(startTimer, (process.env.HWVERSION==2) ? BTN1 : BTN2); + outOfTime(); + return; + } + timerMode = 'active'; + startTimer(); + return; + } + } + + timerLayout.clear(timerLayout.time); + timerLayout.time.label = counter; + timerLayout.render(); + counter--; +} + +/** Start the interval timer. */ +function startTimer() { + timerIsPaused = false; + g.clear(); + if(timerMode === 'active'){ + counter = activeTime; + timerLayout.time.col = '#f00'; + } + else{ + counter = restTime; + timerLayout.time.col = '#0f0'; + } + + timerLayout.clear(timerLayout.set); + timerLayout.set.label = `Sets: ${setsRemaining}`; + timerLayout.render(); + Bangle.buzz(); + countDown(); + if (!counterInterval){ + counterInterval = setInterval(countDown, 1000); + } +} + +/** Menu step in which user sets the number of sets to be performed. */ +function setNumSets(){ + g.clear(); + var menuLayout = new Layout( { + type:"v", c: [ + {type:"txt", font:"6x8:2", label:"Number Sets", id:"title" }, + {type:"txt", font:"30%", pad: 20, label: numSets, id:"value" }, + {type:"btn", font:"6x8:2", label:"Back", cb: l => { + setRestTime(); + } + } + ] + }, {btns: [ + {label:"+", cb: l=> { + incrementNumSets(); + }}, + {label:"Go", cb: l=> { + setsRemaining = numSets; + initTimerLayout(); + startTimer(); + }}, + {label:"-", cb: l=>{ + decrementNumSets(); + }} + ]}); + menuLayout.render(); + + const incrementNumSets = () => { + ++numSets; + menuLayout.clear(menuLayout.numSets); + menuLayout.value.label = numSets; + menuLayout.render(); + }; + + const decrementNumSets = () => { + if(numSets === 1){ + return; + } + --numSets; + menuLayout.clear(menuLayout.numSets); + menuLayout.value.label = numSets; + menuLayout.render(); + }; +} + +/** Menu step in which user sets the number of seconds of rest time for each set. */ +function setRestTime(){ + g.clear(); + var menuLayout = new Layout( { + type:"v", c: [ + {type:"txt", font:"6x8:2", label:"Rest Time", id:"title" }, + {type:"txt", font:"30%", pad: 20, label: restTime, id:"value" }, + {type:"btn", font:"6x8:2", label:"Back", cb: l => { + setActiveTime(); + } + } + ] + }, {btns: [ + {label:"+", cb: l=> { + incrementRestTime(); + }}, + {label:"OK", cb: l=>setNumSets()}, + {label:"-", cb: l=>{ + decrementRestTime(); + }} + ]}); + menuLayout.render(); + + const incrementRestTime = () => { + restTime += 5; + menuLayout.clear(menuLayout.restTime); + menuLayout.value.label = restTime; + menuLayout.render(); + }; + + const decrementRestTime = () => { + if(restTime === 0){ + return; + } + restTime -= 5; + menuLayout.clear(menuLayout.restTime); + menuLayout.value.label = restTime; + menuLayout.render(); + }; +} + +/** Menu step in which user sets the number of seconds of active time for each set. */ +function setActiveTime(){ + g.clear(); + var menuLayout = new Layout( { + type:"v", c: [ + {type:"txt", font:"6x8:2", label:"Active Time", id:"title" }, + {type:"txt", font:"30%", pad: 20, label: activeTime, id:"value" } + ] + }, {btns: [ + {font:"20%", label:"+", fillx:1, cb: l=> { + incrementActiveTime(); + }}, + {label:"OK", cb: l => setRestTime()}, + {type:"btn", font:"20%", label:"-", fillx:1, cb: l=> { + decrementActiveTime(); + } + } + ]}); + menuLayout.render(); + + const incrementActiveTime = () => { + activeTime += 5; + menuLayout.clear(menuLayout.activeTime); + menuLayout.value.label = activeTime; + menuLayout.render(); + }; + + const decrementActiveTime = () => { + if(activeTime === 0){ + return; + } + activeTime -= 5; + menuLayout.clear(menuLayout.activeTime); + menuLayout.value.label = activeTime; + menuLayout.render(); + }; +} + +/** Start the setup menu, walks through setting active time, rest time, and number of sets. */ +function setup(){ + if (timerLayout){ + // remove timerLayout, otherwise it's pause button callback will still be registered + timerLayout.remove(timerLayout); + timerLayout = undefined; + } + Bangle.setUI(); // remove all existing input handlers + timerMode = 'active'; + setActiveTime(); +} + +// this keeps the watch LCD lit up +Bangle.setLCDPower(1); +setup(); \ No newline at end of file From bff43e662da03dfd1648ef656062195689448236 Mon Sep 17 00:00:00 2001 From: James G Date: Fri, 26 Nov 2021 12:42:13 -0500 Subject: [PATCH 2/4] Fix url for intervalTimer.app.js in app.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index a0bd5bfd0..4c709ef12 100644 --- a/apps.json +++ b/apps.json @@ -4468,7 +4468,7 @@ "readme":"README.md", "supports":["BANGLEJS2"], "storage": [ - {"name":"intervalTimer.app.js","url":"app.js"}, + {"name":"intervalTimer.app.js","url":"intervalTimer.app.js"}, {"name":"intervalTimer.img","url":"app-icon.js","evaluate":true} ] } From 2ae9585193c1394bca43a9160dcfbcdd29f14803 Mon Sep 17 00:00:00 2001 From: James G Date: Fri, 26 Nov 2021 12:43:36 -0500 Subject: [PATCH 3/4] rename intervalTimer.app.js to app.js --- apps.json | 2 +- apps/intervalTimer/{intervalTimer.app.js => app.js} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename apps/intervalTimer/{intervalTimer.app.js => app.js} (100%) diff --git a/apps.json b/apps.json index 4c709ef12..a0bd5bfd0 100644 --- a/apps.json +++ b/apps.json @@ -4468,7 +4468,7 @@ "readme":"README.md", "supports":["BANGLEJS2"], "storage": [ - {"name":"intervalTimer.app.js","url":"intervalTimer.app.js"}, + {"name":"intervalTimer.app.js","url":"app.js"}, {"name":"intervalTimer.img","url":"app-icon.js","evaluate":true} ] } diff --git a/apps/intervalTimer/intervalTimer.app.js b/apps/intervalTimer/app.js similarity index 100% rename from apps/intervalTimer/intervalTimer.app.js rename to apps/intervalTimer/app.js From 4f5ec608de77dd4febf68db0b6d3aa9703b73b16 Mon Sep 17 00:00:00 2001 From: James G Date: Fri, 26 Nov 2021 12:48:20 -0500 Subject: [PATCH 4/4] fix formatting in README for interval timer app --- apps/intervalTimer/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/intervalTimer/README.md b/apps/intervalTimer/README.md index f56dd74d2..d57c16e9c 100644 --- a/apps/intervalTimer/README.md +++ b/apps/intervalTimer/README.md @@ -6,28 +6,28 @@ An interval timer for workouts and whatever else! First set the active time (i.e. the number of seconds to perform exercises). -![Set Active Time](images\set-active.png) +![Set Active Time](images/set-active.png) Next set the rest time (i.e. number of seconds to rest between exercises). -![Set Rest Time](images\set-rest.png) +![Set Rest Time](images/set-rest.png) Finally choose the number of sets to perform. -![Set Number Sets](images\set-sets.png) +![Set Number Sets](images/set-sets.png) Active time will be shown in red, rest time in green. The watch will buzz whenever active or rest time gets to 0. -![Timer (active)](images\timer1.png) -![Timer (rest)](images\timer2.png) +![Timer (active)](images/timer1.png) +![Timer (rest)](images/timer2.png) You can press the physical button during timer countdown to pause the timer. -![Paused](images\pause.png) +![Paused](images/pause.png) View after all sets are completed. Press menu to change settings or restart to start timer again with the same settings. -![Completed view](images\done.png) +![Completed view](images/done.png) ## Creator