From 2167f4ca7b64029bade677517712df104fd07dda Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Tue, 18 Oct 2022 18:44:24 +0300 Subject: [PATCH 001/179] Create app.js --- apps/rinkulainen/app.js | 146 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 apps/rinkulainen/app.js diff --git a/apps/rinkulainen/app.js b/apps/rinkulainen/app.js new file mode 100644 index 000000000..6a13da68b --- /dev/null +++ b/apps/rinkulainen/app.js @@ -0,0 +1,146 @@ +// Rinkulainen +// +// Bangle.js 2 watch face +// by Jukio Kallio +// www.jukiokallio.com + +// settings +const watch = { + theme: "default", + x:0, y:0, w:0, h:0, + color:"#000000", // change background color + finland:true, // change if you want Finnish style date, or US style + + // default theme "grayscale" + hour: { size:60, weight:20, color:"#999999", cursor:8 }, + minute: { size:40, weight:20, color:"#dddddd", cursor:8 }, + second: { on: false, cursor:2 }, // if on, uses a lot more battery + date: { font:"6x8", size:1, y:15, color:"#ffffff" } +}; + +// more themes +if (watch.theme == "colorful") { + watch.hour = { size:60, weight:8, color:"#00FFFF", cursor:10 }; + watch.minute = { size:40, weight:16, color:"#FFFF00", cursor:6 }; + watch.second = { on: false, cursor:2 }; // if on, uses a lot more battery + watch.date = { font:"6x8", size:1, y:15, color:"#FFFF00" }; +} else if (watch.theme == "maze") { + watch.hour = { size:50, weight:7, color:"#ffffff", cursor:6 }; + watch.minute = { size:30, weight:7, color:"#ffffff", cursor:6 }; + watch.second = { on: false, cursor:2 }; // if on, uses a lot more battery + watch.date = { font:"6x8", size:1, y:15, color:"#ffffff" }; +} else if (watch.theme == "disks") { + watch.hour = { size:72, weight:30, color:"#00ff66", cursor:4 }; + watch.minute = { size:36, weight:32, color:"#0066ff", cursor:4 }; + watch.second = { on: false, cursor:2 }; // if on, uses a lot more battery + watch.date = { font:"6x8", size:1, y:10, color:"#ffffff" }; +} + +// set some additional settings +watch.w = g.getWidth(); // size of the background +watch.h = g.getHeight(); +watch.x = watch.w * 0.5; // position of the circles +watch.y = watch.h * 0.46; +watch.date.y = watch.date.y + watch.y + watch.hour.size; // final position of the date + +const dateWeekday = { 0: "Sunday", 1: "Monday", 2: "Tuesday", 3: "Wednesday", 4:"Thursday", 5:"Friday", 6:"Saturday" }; // weekdays + +var wait = 60000; // wait time, normally a minute +if (watch.second.on) wait = 1000; // a second if seconds are used + + +// timeout used to update every minute +var drawTimeout; + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, wait - (Date.now() % wait)); +} + + +// main function +function draw() { + // make date object + var date = new Date(); + + // work out the date string + var dateDay = date.getDate(); + var dateMonth = date.getMonth() + 1; + var dateYear = date.getFullYear(); + var dateStr = dateWeekday[date.getDay()] + " " + dateMonth + "." + dateDay + "." + dateYear; + if (watch.finland) dateStr = dateWeekday[date.getDay()] + " " + dateDay + "." + dateMonth + "." + dateYear; // the true way of showing date + + // Reset the state of the graphics library + g.reset(); + + // Clear the area where we want to draw the time + g.setColor(watch.color); + g.fillRect(0, 0, watch.w, watch.h); + + // variables for vertex transformation + var tver, tobj, tran; + + // draw hour circle + g.setColor(watch.hour.color).fillCircle(watch.x, watch.y, watch.hour.size); + g.setColor(watch.color).fillCircle(watch.x, watch.y, watch.hour.size - watch.hour.weight); + // draw hour line + g.setColor(watch.color); + var thour = (date.getHours() / 12) * (Math.PI * 2); + tver = [-watch.hour.cursor, 0, watch.hour.cursor, 0, watch.hour.cursor, -watch.hour.size*1.05, -watch.hour.cursor, -watch.hour.size*1.05]; + tobj = { x:watch.x, y:watch.y, scale:1, rotate:thour }; + tran = g.transformVertices(tver, tobj); + g.fillPoly(tran); + + // draw minute circle + g.setColor(watch.minute.color).fillCircle(watch.x, watch.y, watch.minute.size); + g.setColor(watch.color).fillCircle(watch.x, watch.y, watch.minute.size - watch.minute.weight); + // draw minute line + g.setColor(watch.color); + var tmin = (date.getMinutes() / 60) * (Math.PI * 2); + tver = [-watch.minute.cursor, 0, watch.minute.cursor, 0, watch.minute.cursor, -watch.minute.size*1.05, -watch.minute.cursor, -watch.minute.size*1.05]; + tobj = { x:watch.x, y:watch.y, scale:1, rotate:tmin }; + tran = g.transformVertices(tver, tobj); + g.fillPoly(tran); + + // draw seconds line, if the feature is on + if (watch.second.on) { + g.setColor(watch.color); + var tsec = (date.getSeconds() / 60) * (Math.PI * 2); + tver = [-watch.second.cursor, 0, watch.second.cursor, 0, watch.second.cursor, -watch.second.size*1.045, -watch.second.cursor, -watch.second.size*1.045]; + tobj = { x:watch.x, y:watch.y, scale:1, rotate:tsec }; + tran = g.transformVertices(tver, tobj); + g.fillPoly(tran); + } + + // draw date + g.setFontAlign(0,0).setFont(watch.date.font, 1).setColor(watch.date.color); + g.drawString(dateStr, watch.x, watch.date.y + watch.date.size + 2); + + // queue draw + queueDraw(); +} + + +// Clear the screen once, at startup +g.clear(); +// draw immediately at first +draw(); + + +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); + + +// Show launcher when middle button pressed +Bangle.setUI("clock"); From 12a0ce6c303995ecc319880bdc405beaa0f0f2e7 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Tue, 18 Oct 2022 18:53:26 +0300 Subject: [PATCH 002/179] Create app-icon.js --- apps/rinkulainen/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/rinkulainen/app-icon.js diff --git a/apps/rinkulainen/app-icon.js b/apps/rinkulainen/app-icon.js new file mode 100644 index 000000000..b27f89b2d --- /dev/null +++ b/apps/rinkulainen/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkBIPsPAAwVN+AAKFaIxPFpYvJFpovJFpovHFp4vHFp4vGFyIvFFyIvEFyQvEFyQvDFyYvDFyYvCFygvCFygvBFyovBFyvwFy0Pc6YvTC4ajDFpv//4XFF8otBF44HBFywvKFof/R4gXBF8QuEF/4vZFwovwC4wvgFwwvGBBAhDF5oXGF/4v/FAovRFAbtCF6hoKF5QAG")) From 720d60e71f50e586054fcd4c475a62f7de7f363d Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Tue, 18 Oct 2022 19:02:04 +0300 Subject: [PATCH 003/179] Create metadata.json --- apps/rinkulainen/metadata.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 apps/rinkulainen/metadata.json diff --git a/apps/rinkulainen/metadata.json b/apps/rinkulainen/metadata.json new file mode 100644 index 000000000..1e7d16865 --- /dev/null +++ b/apps/rinkulainen/metadata.json @@ -0,0 +1,16 @@ +{ "id": "rinkulainen", + "name": "Rinkulainen - Minimal & Stylish watch face", + "shortName":"Rinkulainen", + "version":"0.01", + "description": "A minimal watch face, with rings/disks for hours and minutes. Date underneath. With easy to mod source code for making your own themes. Some example themes included.", + "icon": "app.png", + "screenshots": [{"url":"screenshot1.png"}, {"url":"screenshot2.png"}, {"url":"screenshot3.png"}], + "type": "clock", + "tags": "clock", + "supports" : ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"rinkulainen.app.js","url":"app.js"}, + {"name":"rinkulainen.img","url":"app-icon.js","evaluate":true} + ] +} From 8d1c52e62059d9c92ae18b457ffcd42505df8032 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Tue, 18 Oct 2022 19:02:26 +0300 Subject: [PATCH 004/179] Add screenshots --- apps/rinkulainen/screenshot1.png | Bin 0 -> 6471 bytes apps/rinkulainen/screenshot2.png | Bin 0 -> 6374 bytes apps/rinkulainen/screenshot3.png | Bin 0 -> 6009 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/rinkulainen/screenshot1.png create mode 100644 apps/rinkulainen/screenshot2.png create mode 100644 apps/rinkulainen/screenshot3.png diff --git a/apps/rinkulainen/screenshot1.png b/apps/rinkulainen/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..f897c5a4e096ecaef3407aeb492bd675a320a213 GIT binary patch literal 6471 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 literal 0 HcmV?d00001 diff --git a/apps/rinkulainen/screenshot2.png b/apps/rinkulainen/screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..354618167d078c21f984546174024d2c5dd02e86 GIT binary patch literal 6374 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 Y+9lR>i;m~~xmGDYSCg%IW*YYY0G1T%a{vGU literal 0 HcmV?d00001 diff --git a/apps/rinkulainen/screenshot3.png b/apps/rinkulainen/screenshot3.png new file mode 100644 index 0000000000000000000000000000000000000000..ef1385288029f070de4b59d2312a8f05faa46ec9 GIT binary patch literal 6009 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 W!A{U%o%MI8ulhhssrtTk_ Date: Tue, 18 Oct 2022 19:04:48 +0300 Subject: [PATCH 005/179] Create README.md --- apps/rinkulainen/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 apps/rinkulainen/README.md diff --git a/apps/rinkulainen/README.md b/apps/rinkulainen/README.md new file mode 100644 index 000000000..fde01262c --- /dev/null +++ b/apps/rinkulainen/README.md @@ -0,0 +1,8 @@ +# Rinkulainen + +A Minimal & stylish watch face. + +![Default grayscale theme](screenshot1.png) + +![Colorful theme](screenshot1.png) +![Maze theme](screenshot2.png) From 4c93dd52c37ee1ca571391224f9afbda767252f5 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Tue, 18 Oct 2022 19:05:03 +0300 Subject: [PATCH 006/179] Update README.md --- apps/rinkulainen/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/rinkulainen/README.md b/apps/rinkulainen/README.md index fde01262c..50aee14cd 100644 --- a/apps/rinkulainen/README.md +++ b/apps/rinkulainen/README.md @@ -4,5 +4,5 @@ A Minimal & stylish watch face. ![Default grayscale theme](screenshot1.png) -![Colorful theme](screenshot1.png) -![Maze theme](screenshot2.png) +![Colorful theme](screenshot2.png) +![Maze theme](screenshot3.png) From 2ffde80c7a4d01a483368f13557d7f78d382abf4 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Tue, 18 Oct 2022 19:06:47 +0300 Subject: [PATCH 007/179] Update README.md --- apps/rinkulainen/README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/rinkulainen/README.md b/apps/rinkulainen/README.md index 50aee14cd..6c48447c4 100644 --- a/apps/rinkulainen/README.md +++ b/apps/rinkulainen/README.md @@ -1,8 +1,7 @@ # Rinkulainen -A Minimal & stylish watch face. +A Minimal & stylish watch face, with rings or disks for hours and minutes. Date underneath. With easy to mod source code for making your own themes. Some example themes included. -![Default grayscale theme](screenshot1.png) - -![Colorful theme](screenshot2.png) -![Maze theme](screenshot3.png) +![](screenshot1.png) Default grayscale theme +![](screenshot2.png) Colorful theme +![](screenshot3.png) Maze theme From 5d1f736b6106a7c43746326ee1d00e6f58efcb64 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Tue, 18 Oct 2022 19:07:20 +0300 Subject: [PATCH 008/179] Update README.md --- apps/rinkulainen/README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/rinkulainen/README.md b/apps/rinkulainen/README.md index 6c48447c4..b41fa3461 100644 --- a/apps/rinkulainen/README.md +++ b/apps/rinkulainen/README.md @@ -1,7 +1,14 @@ # Rinkulainen +By Jukio Kallio + A Minimal & stylish watch face, with rings or disks for hours and minutes. Date underneath. With easy to mod source code for making your own themes. Some example themes included. -![](screenshot1.png) Default grayscale theme -![](screenshot2.png) Colorful theme -![](screenshot3.png) Maze theme +![](screenshot1.png) +Default grayscale theme + +![](screenshot2.png) +Colorful theme + +![](screenshot3.png) +Maze theme From 13c739f186e72396f116773b6dbbc11db4611c55 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Wed, 19 Oct 2022 10:32:45 +0300 Subject: [PATCH 009/179] Add files via upload --- apps/rinkulainen/app.png | Bin 0 -> 4656 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/rinkulainen/app.png diff --git a/apps/rinkulainen/app.png b/apps/rinkulainen/app.png new file mode 100644 index 0000000000000000000000000000000000000000..632cf17e033e1997ec76c7061c91ee76d125ea1c GIT binary patch literal 4656 zcmai2X&{vC8Xo(aEJ>1#5vhzZCSn+3>^s?)G8khrW`-FIT1Z0K_pM|J+1Kpbr%=ig zp=67svLz(z8S2#e&i8%i{CH>H=ee%?dhYGHf4rea2AT(0kFo*)fCJiEY9`cwslA7p zmijwvkM9Kl=<~6rmSjtPJ-8#mO%mlqa6n5^+=x^h08mt>5K)e)kC?LfRhbO@)2++PR zocg}E4FLi7DP&g!$Wq@3h$MKRfijXZl2RZgR-mGXlQY~zP2;CAb%g-AkjX?i1mf-O zE$I!DBzRyTPCSR55o!;*+Nl+QkcS}r)%0_*Ifh9XljX(?(~LZ!e^Ia8<{ zTt*6hR{D$-3@#=0n@zn1PAD?!|MB;F8K_9r*Vl(@VM%0yhtK}jj|RVhcK@;ZvBY8b zI~xexuP+?sxR)9Pi0DCZ@^nNy?H^8+`+<@O&SY0>EU!66K$6OW-XS+P>_s&9H%us z&BGgcH%~+vIcPD1yvW9_Rd>YA$!2PORe*ByIkfTIHcCa^ijPg!bnGTQdA0FdkHYvl z?`!g;4Fm~B=Wk$93^WY*L>qMy9MuuTRMDQDU9M#apbhb-!2zD}i94kY4~qjHUf(&{ zSkLi5*v{Sf^@h*(^_V83Y)*iGwu&v#lzAE0L=U(Kih9Zh0E(S&TFs_SX5~}C0fT8& z8_ow+3{V1DF?nB_l#*}CNj}B^fc@)Nd=3NNSO}+^iFe-csvK9HJI$+;4VWE1e+@JAx6y^?+NK~#>#z-^M zaNh?=N3pHj`)}`FxL901o-26lY?&g+!0e!9f2ur>h*=V&d+u2gxQ3Zuh_cqrPu~Cl z9o{n{+^?4N9-eOvTBX+uu?yOY(hAWR=7^oq(8R9uC&x$~e_ZO<3(}^6sAMS^W;2Hm z4cm&OAK~kdguSS?k*_FSw3|BNb z{Qg$Kx;ba6IO~*5-FgV^aN*@mN?ajORz>jSy?ZZ&_zNPKAoRxmY<{;G;)qWEp+EsG zYq$V>60)juWKKlBlNL0QIl1C`;#-l{B<%R1z-AzKYxn0NwgnsB0M*W2=@v6(yYtTD zmr>~&928pj;~_T@XKuLXRc6zT#k4qfMsH2q0UTchA*jTg;H6>LRLm!d9e`3$Gs)*LghzeaIznt?ev7 z=1Mvg&*bL&uC+$Fk^?-Y_m;k9;&|^trh_-{A%qhPLT%y|J}XblN40v(40RgYo)SlM ziiW&f%F1~Z`{;u|ubFytNhEwQEFj;5$^6<%&vtRQs+{JIc<76^HHX|X$6>2E;2^+q zn5&Sh-e1sUGT^xH+acuk*t?B)PXoM8D1V=Fy^??WA+gAFp156TMaPhtN&AX%${VVrok2(=V`_Ue<5bt4EqxyG%P@d zuwc)_ZPyY4we3$QG3cnsTe6$`zp_UR(?1HhYk$xMz|;yQvZgU5w#X2f)(jOWG<7Ws zy@5bxmJAX0$4AP}S7w8XiC9t)q+g2x1DafwRvCWps~=tjTl)W~N1E-3GR z4A~7T>I6^IybNg2P|7%>gFIja8{iPURc_32G*s;VRIkKYA+W}W`)qwWl}ASd2D3VP zzs|~39=ICd32mRh@T~K0(ToLM7wu)qp~u{S1ZW;Xc7pUkaonewZJ0M% zPEO)4pKK7}4%N#<^a(7qA99d&XLYA>2fOoq5ig5h4;j`6MTcp3pSW(q9%^_R7$0LE z?G+UfB^mohTd338iLG2fJ}gZqAx5{8cY1!hZMthZcl!8k$tMZ#bVDYqXKoKzU+;YzEEEuU$&J; zpYOi%%Q1Xe-GA^E->06w@$BoiyIgdRmarOj8b?`2*wl%vQGXYELJO=@R{Y#Bw%4H- zoky5OB{^9-S)wVOrQxB_`6NYWNfH<7;8*z9eqe=4no6e1SEg47>J(=i`|PuTBGJal zeUe$O8tGwH?HTRz?YdzCVT;KVVg_Pa`eMn2FnR1t`CV~_aanc!yLwZ4 zxk-5GM*BBz&iKQ4F_;b7>uq6w8uqx;J-4Q}Tctk13~itmRfn>-??RrC5`^!xJwuz7 z87yz{O(;XyIQnu$5e;Bk8DC#wV7#Vii|)z+>53}PYyio z*Pb(dPwwOQT=PhfEAhk&svdan3_Lqc;vcA-m({-6h;e!Gd40pGYXK4!B#=&pjWp%gZyq8vM3)_ z2?+_ati zU)wkRSWLs&TDRw=(Ej!`L#TFi_Su{mlUS4LY_G@zg7pqKzZ8r$_RXsM+SKj#yMhF1 zCGV{a7C6s3&sq-8%h>+v-0L$PO9kIY`5VGy`0Z$m?H^18Nom#C4ht{yfq4-xR(fnx zzDsl|yIPqC%Nf}UFT@c=3q(uGMaqXT%{`${U#Ik^rl!@OiA+np=Y2jO@*?_Pl8aKA zi$lS4EA!K?UEf|@iXIn@j3XEWZ@b@ar=_DLHQy&2?POjtI$~sLwvIA+ncb-FtNt>R zE%vThPx@A+T;Y24sr5sxaWfASE@1SpN`=GRrpQjd?JG0S_C+JyZ4EJH7ex&X6?fb*;zH z^6ljwHhQ-1ZTQyEvrB$_&XPE*=_;2|hj$Ji-+k7lO~l#cS65O#W}&kZUO_Nmh|P}I zlbgJlGm57NOR|eii*W^E`8Zp2#pN&gJq1q+O3WB6=B*v;oOe>bxdypHO4zI|s>g6w zzi$`{oDjg{*~cv}xmnnih1NVI_Q$@^PBq+Z-zjpw^E6=@eCd%+^&_`CBVL*9^*PS< zAJ^2YT#CvcIcmO%&{aTs$qv>IxV?Sy)~rcj&V1q8j^D=O&^NUO>{!>BO?8jgc*=Iz zHhNWSdwQdo(H&{ysN?uKAet#9bt`3U7rGKz!~{NQE-0;7IV-igl-Aa$c{`FU6fZch znBX~Q{PpIHLPy83W?zSu(1h6NlRasy3Z7eMKdeNtyw{s60y56frC=7EAx_|sW{9zvA1o4II?!Me~eW4qixVgizv8g(gRJ>-fY|&W4 z*8sg%v0BtIGP5weu(`NAw%P#MwBJIFXs&hir^hHG=95>FS8A83@s-^ zkND?_(x4bDyWxzoS!6F54C$)kLJw8$)a;BPboame|_qPrkVhNZv1g_ za?p`FzBgZ9Z~0{CYNhsnGky~SFaqSyS6tIG)6PhlvSEXElt(?u59-v731UxD9Qp*2 zR2y4=x$bWpCO%y?`Be3=RVT Date: Wed, 19 Oct 2022 10:54:04 +0300 Subject: [PATCH 010/179] Changed default theme to the 'colorful' --- apps/rinkulainen/app.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/rinkulainen/app.js b/apps/rinkulainen/app.js index 6a13da68b..b487c9a0d 100644 --- a/apps/rinkulainen/app.js +++ b/apps/rinkulainen/app.js @@ -11,19 +11,19 @@ const watch = { color:"#000000", // change background color finland:true, // change if you want Finnish style date, or US style - // default theme "grayscale" - hour: { size:60, weight:20, color:"#999999", cursor:8 }, - minute: { size:40, weight:20, color:"#dddddd", cursor:8 }, + // default theme "colorful" + hour: { size:60, weight:8, color:"#00FFFF", cursor:10 }, + minute: { size:40, weight:16, color:"#FFFF00", cursor:6 }, second: { on: false, cursor:2 }, // if on, uses a lot more battery - date: { font:"6x8", size:1, y:15, color:"#ffffff" } + date: { font:"6x8", size:1, y:15, color:"#FFFF00" } }; // more themes -if (watch.theme == "colorful") { - watch.hour = { size:60, weight:8, color:"#00FFFF", cursor:10 }; - watch.minute = { size:40, weight:16, color:"#FFFF00", cursor:6 }; +if (watch.theme == "grayscale") { + watch.hour = { size:60, weight:20, color:"#999999", cursor:8 }; + watch.minute = { size:40, weight:20, color:"#dddddd", cursor:8 }; watch.second = { on: false, cursor:2 }; // if on, uses a lot more battery - watch.date = { font:"6x8", size:1, y:15, color:"#FFFF00" }; + watch.date = { font:"6x8", size:1, y:15, color:"#ffffff" }; } else if (watch.theme == "maze") { watch.hour = { size:50, weight:7, color:"#ffffff", cursor:6 }; watch.minute = { size:30, weight:7, color:"#ffffff", cursor:6 }; From 0ef345e2a73a695421693312d30ca63212bed79c Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Wed, 19 Oct 2022 10:54:45 +0300 Subject: [PATCH 011/179] Changed order of the screenshots --- apps/rinkulainen/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/rinkulainen/README.md b/apps/rinkulainen/README.md index b41fa3461..4b32ada0a 100644 --- a/apps/rinkulainen/README.md +++ b/apps/rinkulainen/README.md @@ -4,11 +4,11 @@ By Jukio Kallio A Minimal & stylish watch face, with rings or disks for hours and minutes. Date underneath. With easy to mod source code for making your own themes. Some example themes included. -![](screenshot1.png) -Default grayscale theme - ![](screenshot2.png) -Colorful theme +Default Colorful theme + +![](screenshot1.png) +Grayscale theme ![](screenshot3.png) Maze theme From 9ab0242e46e32ae6904f4eef15d1caa9e25e903d Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Wed, 19 Oct 2022 10:55:10 +0300 Subject: [PATCH 012/179] Changed order of the screenshots --- apps/rinkulainen/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/rinkulainen/metadata.json b/apps/rinkulainen/metadata.json index 1e7d16865..f0a51af87 100644 --- a/apps/rinkulainen/metadata.json +++ b/apps/rinkulainen/metadata.json @@ -4,7 +4,7 @@ "version":"0.01", "description": "A minimal watch face, with rings/disks for hours and minutes. Date underneath. With easy to mod source code for making your own themes. Some example themes included.", "icon": "app.png", - "screenshots": [{"url":"screenshot1.png"}, {"url":"screenshot2.png"}, {"url":"screenshot3.png"}], + "screenshots": [{"url":"screenshot2.png"}, {"url":"screenshot1.png"}, {"url":"screenshot3.png"}], "type": "clock", "tags": "clock", "supports" : ["BANGLEJS","BANGLEJS2"], From ca41ccf6de3acd927baa3860dc4951778d4236fd Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Wed, 19 Oct 2022 13:37:42 +0300 Subject: [PATCH 013/179] Create app.js --- apps/henkinen/app.js | 125 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 apps/henkinen/app.js diff --git a/apps/henkinen/app.js b/apps/henkinen/app.js new file mode 100644 index 000000000..1207b5686 --- /dev/null +++ b/apps/henkinen/app.js @@ -0,0 +1,125 @@ +// Henkinen +// +// Bangle.js 2 breathing helper +// by Jukio Kallio +// www.jukiokallio.com + +// settings +const breath = { + theme: "default", + x:0, y:0, w:0, h:0, + size: 60, + + bgcolor: {r: 1, g: 0.6, b: 0.3}, + incolor: {r: 1, g: 0.8, b: 0.5}, + keepcolor: {r: 1, g: 0.8, b: 0.5}, + outcolor: {r: 1, g: 0.8, b: 0.5}, + + font: "Vector", fontsize: 14, + textcolor: {r: 1, g: 1, b: 1}, + texty: 16, + + in: 4000, + keep: 7000, + out: 8000 +}; + +// set some additional settings +breath.w = g.getWidth(); // size of the background +breath.h = g.getHeight(); +breath.x = breath.w * 0.5; // position of the circles +breath.y = breath.h * 0.45; +breath.texty = breath.y + breath.size + breath.texty; // text position + +var wait = 100; // wait time, normally a minute +var time = 0; // for time keeping + + +// timeout used to update every minute +var drawTimeout; + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, wait - (Date.now() % wait)); +} + + +// main function +function draw() { + // make date object + var date = new Date(); + + // update current time + time += wait - (Date.now() % wait); + if (time > breath.in + breath.keep + breath.out) time = 0; // reset time + + // Reset the state of the graphics library + g.reset(); + + // Clear the area where we want to draw the time + g.setColor(breath.bgcolor.r, breath.bgcolor.g, breath.bgcolor.b); + g.fillRect(0, 0, breath.w, breath.h); + + // calculate circle size + var circle = 0; + if (time < breath.in) { + // breath in + circle = time / breath.in; + g.setColor(breath.incolor.r, breath.incolor.g, breath.incolor.b); + + } else if (time < breath.in + breath.keep) { + // keep breath + circle = 1; + g.setColor(breath.keepcolor.r, breath.keepcolor.g, breath.keepcolor.b); + + } else if (time < breath.in + breath.keep + breath.out) { + // breath out + circle = ((breath.in + breath.keep + breath.out) - time) / breath.out; + g.setColor(breath.outcolor.r, breath.outcolor.g, breath.outcolor.b); + + } + + // draw breath circle + g.fillCircle(breath.x, breath.y, breath.size * circle); + + // breath area + g.setColor(breath.textcolor.r, breath.textcolor.g, breath.textcolor.b); + g.drawCircle(breath.x, breath.y, breath.size); + + // draw text + g.setFontAlign(0,0).setFont(breath.font, breath.fontsize).setColor(breath.textcolor.r, breath.textcolor.g, breath.textcolor.b); + + if (time < breath.in) { + // breath in + g.drawString("Breath in", breath.x, breath.texty); + + } else if (time < breath.in + breath.keep) { + // keep breath + g.drawString("Keep it in", breath.x, breath.texty); + + } else if (time < breath.in + breath.keep + breath.out) { + // breath out + g.drawString("Breath out", breath.x, breath.texty); + + } + + // queue draw + queueDraw(); +} + + +// Clear the screen once, at startup +g.clear(); +// draw immediately at first +draw(); + + +// keep LCD on +Bangle.setLCDPower(1); + +// Show launcher when middle button pressed +Bangle.setUI("clock"); From 52532b41c59a0115d7ee352af0a739281af8ce2c Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Wed, 19 Oct 2022 13:41:11 +0300 Subject: [PATCH 014/179] Create metadata.json --- apps/henkinen/metadata.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 apps/henkinen/metadata.json diff --git a/apps/henkinen/metadata.json b/apps/henkinen/metadata.json new file mode 100644 index 000000000..f6559be72 --- /dev/null +++ b/apps/henkinen/metadata.json @@ -0,0 +1,15 @@ +{ "id": "henkinen", + "name": "Henkinen - Tiny Breathing Helper", + "shortName":"Henkinen", + "version":"0.01", + "description": "A tiny app helping you to breath and relax.", + "icon": "app.png", + "screenshots": [{"url":"screenshot1.png"}], + "type": "outdoors", + "supports" : ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"henkinen.app.js","url":"app.js"}, + {"name":"henkinen.img","url":"app-icon.js","evaluate":true} + ] +} From d3a7e4fa334c7070a1c4ecad797d47aa0efb73d2 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Wed, 19 Oct 2022 13:42:23 +0300 Subject: [PATCH 015/179] Create README.md --- apps/henkinen/README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 apps/henkinen/README.md diff --git a/apps/henkinen/README.md b/apps/henkinen/README.md new file mode 100644 index 000000000..e17e86121 --- /dev/null +++ b/apps/henkinen/README.md @@ -0,0 +1,7 @@ +# Henkinen + +By Jukio Kallio + +A tiny app helping you to breath and relax. + +![](screenshot1.png) From efe67c3a3c537dca3192e664c7d7be4b53af6996 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Wed, 19 Oct 2022 13:43:31 +0300 Subject: [PATCH 016/179] Added screenshot --- apps/henkinen/screenshot1.png | Bin 0 -> 23611 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/henkinen/screenshot1.png diff --git a/apps/henkinen/screenshot1.png b/apps/henkinen/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..bb6655f6ab41b1c605107503efb672c81a9c33fd GIT binary patch literal 23611 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 literal 0 HcmV?d00001 From 78a3ea812ad3747afd159c03c389a797507ebb14 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Wed, 19 Oct 2022 13:47:15 +0300 Subject: [PATCH 017/179] Added loader icon --- apps/henkinen/app.png | Bin 0 -> 5730 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/henkinen/app.png diff --git a/apps/henkinen/app.png b/apps/henkinen/app.png new file mode 100644 index 0000000000000000000000000000000000000000..6ac3f151f052aa624e66a244ed1aaed6c84ea41a GIT binary patch literal 5730 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 H{oVfo=&1`l literal 0 HcmV?d00001 From 0c4cb7df5a775bfefb23feb709b06902996b1fcd Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Wed, 19 Oct 2022 13:49:44 +0300 Subject: [PATCH 018/179] Create app-icon.js --- apps/henkinen/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/henkinen/app-icon.js diff --git a/apps/henkinen/app-icon.js b/apps/henkinen/app-icon.js new file mode 100644 index 000000000..fd1e32d20 --- /dev/null +++ b/apps/henkinen/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4Az64AIFlgyjEZoxfDqYxaDSowYJDBGg54AGU7osOGRgvQCA4tNGJIwOOA4uRGAyRNFzYwTFzgwILx4uXGApgKFz4wHRspgQL0JgNF9ztgSBwujMBYv/F/4v/F/4v/F6IwiFBRgkE5Iv3GDiOLMEZeLeMReNSMAjLMBYwWERgwhFyRtJFyyNMCBotTFyJwDCZAsODZjDRDFBGYI6waEDZwSSDyAfIBpoxbABItdGRwsiAH4AOA==")) From 5d27e21dda922b5815ed93497d742c4a68b2841c Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Sat, 22 Oct 2022 15:14:00 +0300 Subject: [PATCH 019/179] added tags --- apps/henkinen/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/henkinen/metadata.json b/apps/henkinen/metadata.json index f6559be72..ece0ac5d3 100644 --- a/apps/henkinen/metadata.json +++ b/apps/henkinen/metadata.json @@ -6,6 +6,7 @@ "icon": "app.png", "screenshots": [{"url":"screenshot1.png"}], "type": "outdoors", + "tags": "clock", "supports" : ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ From f9cb4bd84b51cbf0c3a6729bfbea5465b565a5d4 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Sat, 22 Oct 2022 15:14:20 +0300 Subject: [PATCH 020/179] fixed tags --- apps/henkinen/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/henkinen/metadata.json b/apps/henkinen/metadata.json index ece0ac5d3..59b037dda 100644 --- a/apps/henkinen/metadata.json +++ b/apps/henkinen/metadata.json @@ -6,7 +6,7 @@ "icon": "app.png", "screenshots": [{"url":"screenshot1.png"}], "type": "outdoors", - "tags": "clock", + "tags": "outdoors", "supports" : ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ From ad87a01c063eea5dbc7eee904a390ed7e15da424 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Sat, 22 Oct 2022 15:37:54 +0300 Subject: [PATCH 021/179] Update metadata.json --- apps/henkinen/metadata.json | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/henkinen/metadata.json b/apps/henkinen/metadata.json index 59b037dda..1f1bb77fc 100644 --- a/apps/henkinen/metadata.json +++ b/apps/henkinen/metadata.json @@ -5,7 +5,6 @@ "description": "A tiny app helping you to breath and relax.", "icon": "app.png", "screenshots": [{"url":"screenshot1.png"}], - "type": "outdoors", "tags": "outdoors", "supports" : ["BANGLEJS","BANGLEJS2"], "readme": "README.md", From 4fe12172beb52280fe44e7f040baa8fee347cbb6 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Sat, 22 Oct 2022 16:55:47 +0300 Subject: [PATCH 022/179] Create app.js --- apps/poikkipuinen/app.js | 145 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 apps/poikkipuinen/app.js diff --git a/apps/poikkipuinen/app.js b/apps/poikkipuinen/app.js new file mode 100644 index 000000000..7db3384bd --- /dev/null +++ b/apps/poikkipuinen/app.js @@ -0,0 +1,145 @@ +// Poikkipuinen +// +// Bangle.js 2 watch face +// by Jukio Kallio +// www.jukiokallio.com + +require("Font5x9Numeric7Seg").add(Graphics); + +// settings +const watch = { + x:0, y:0, w:0, h:0, + bgcolor:g.theme.bg, + fgcolor:g.theme.fg, + font: "5x9Numeric7Seg", fontsize: 1, + finland:true, // change if you want Finnish style date, or US style +}; + + +// set some additional settings +watch.w = g.getWidth(); // size of the background +watch.h = g.getHeight(); +watch.x = watch.w * 0.5; // position of the circles +watch.y = watch.h * 0.46; + +const dateWeekday = { 0: "Sunday", 1: "Monday", 2: "Tuesday", 3: "Wednesday", 4:"Thursday", 5:"Friday", 6:"Saturday" }; // weekdays + +var wait = 60000; // wait time, normally a minute + + +// timeout used to update every minute +var drawTimeout; + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, wait - (Date.now() % wait)); +} + + +// main function +function draw() { + // make date object + var date = new Date(); + + // work out the date string + var dateDay = date.getDate(); + var dateMonth = date.getMonth() + 1; + var dateYear = date.getFullYear(); + var dateStr = dateWeekday[date.getDay()] + " " + dateMonth + "." + dateDay + "." + dateYear; + if (watch.finland) dateStr = dateWeekday[date.getDay()] + " " + dateDay + "." + dateMonth + "." + dateYear; // the true way of showing date + + // Reset the state of the graphics library + g.reset(); + + // Clear the area where we want to draw the time + g.setColor(watch.bgcolor); + g.fillRect(0, 0, watch.w, watch.h); + + // set foreground color + g.setColor(watch.fgcolor); + g.setFontAlign(1,-1).setFont(watch.font, watch.fontsize); + + // watch face size + var facew, faceh; // halves of the size for easier calculation + facew = 40; + faceh = 59; + + // save hour and minute y positions + var houry, minutey; + + // draw hour meter + g.drawLine(watch.x - facew, watch.y - faceh, watch.x - facew, watch.y + faceh); + var lines = 13; + for (var i = 1; i < lines; i++) { + var w = 2; + var y = -faceh * 2 / (lines-2) * (i-1) + faceh; + + if (i % 3 == 0) { + // longer line and numbers every 3 + w = 5; + g.drawString(i, watch.x - facew - 2, y + watch.y); + } + + g.drawLine(watch.x - facew, y + watch.y, watch.x - facew + w, y + watch.y); + + // get hour y position + if (i == date.getHours() % 12) houry = y; + } + + // draw minute meter + g.drawLine(watch.x + facew, watch.y - faceh, watch.x + facew, watch.y + faceh); + g.setFontAlign(-1,-1); + lines = 60; + for (i = 0; i < lines; i++) { + var mw = 2; + var my = -faceh * 2 / (lines-1) * (i) + faceh; + + if (i % 15 == 0 && i != 0) { + // longer line and numbers every 3 + mw = 5; + g.drawString(i, watch.x + facew + 4, my + watch.y); + } + + g.drawLine(watch.x + facew, my + watch.y, watch.x + facew - mw, my + watch.y); + + // get minute y position + if (i == date.getMinutes()) minutey = my; + } + + // draw the time + var timexpad = 8; + g.drawLine(watch.x - facew + timexpad, watch.y + houry, watch.x + facew - timexpad, watch.y + minutey); + + // draw date + var datey = 12; + g.setFontAlign(0,-1); + g.drawString(dateStr, watch.x, watch.y + faceh + datey); + + // queue draw + queueDraw(); +} + + +// Clear the screen once, at startup +g.clear(); +// draw immediately at first +draw(); + + +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); + + +// Show launcher when middle button pressed +Bangle.setUI("clock"); From 94975ed7bc08bc492b90c4cc0fa74b16beb04137 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Sat, 22 Oct 2022 16:57:43 +0300 Subject: [PATCH 023/179] Create metadata.json --- apps/poikkipuinen/metadata.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 apps/poikkipuinen/metadata.json diff --git a/apps/poikkipuinen/metadata.json b/apps/poikkipuinen/metadata.json new file mode 100644 index 000000000..ec95ab7ce --- /dev/null +++ b/apps/poikkipuinen/metadata.json @@ -0,0 +1,16 @@ +{ "id": "poikkipuinen", + "name": "Poikkipuinen - Minimal watch face", + "shortName":"Poikkipuinen", + "version":"0.01", + "description": "A minimal digital watch face.", + "icon": "app.png", + "screenshots": [{"url":"screenshot1.png"}], + "type": "clock", + "tags": "clock", + "supports" : ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"poikkipuinen.app.js","url":"app.js"}, + {"name":"poikkipuinen.img","url":"app-icon.js","evaluate":true} + ] +} From 2ef63c1fcc329a38e54fc0c4f873b72ddca6aaba Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Sat, 22 Oct 2022 16:59:12 +0300 Subject: [PATCH 024/179] Added screenshot --- apps/poikkipuinen/screenshot1.png | Bin 0 -> 52829 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/poikkipuinen/screenshot1.png diff --git a/apps/poikkipuinen/screenshot1.png b/apps/poikkipuinen/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..e9422ee437cb4f056ab93def1eed716ad4a3b7e0 GIT binary patch literal 52829 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 Date: Sat, 22 Oct 2022 17:00:50 +0300 Subject: [PATCH 025/179] Create README.md --- apps/poikkipuinen/README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 apps/poikkipuinen/README.md diff --git a/apps/poikkipuinen/README.md b/apps/poikkipuinen/README.md new file mode 100644 index 000000000..12f8d5d7e --- /dev/null +++ b/apps/poikkipuinen/README.md @@ -0,0 +1,7 @@ +# Poikkipuinen + +By Jukio Kallio + +A Minimal digital watch face. Follows the theme colors. + +![](screenshot1.png) From 5bf07144fdd6757fd386c489a018599e7dc68504 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Sat, 22 Oct 2022 17:06:30 +0300 Subject: [PATCH 026/179] Added icon png --- apps/poikkipuinen/app.png | Bin 0 -> 2625 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/poikkipuinen/app.png diff --git a/apps/poikkipuinen/app.png b/apps/poikkipuinen/app.png new file mode 100644 index 0000000000000000000000000000000000000000..fa506c8869155bbcb1d255b36b24814a7edbf6f9 GIT binary patch literal 2625 zcmai0d0Z1`8XgRC2^A3(fuE*>qKG*N1WQQdNJxnqpj-(GN{$Ik37MD#h^z{zRlJ4b zg;-kA01I*oB9RhBMMV%?52`_EQP2g7vPwa!?j%^$s=I$olJ9+<_xaxI`zAYr1HZN~ zvoiw#z=9RP2tmJzy2r!_{p3s;+YSJRm2enW!DX+c2#^FkPl)g#yfQ(G;s8MPR!Vt- zcu0ZeL$R=g1`eqkKrAezfgCcM$d=NfI5;3h28E^sh6z&Q1)f6Cdzl$kNkIh?AO#Pr zOb|=t6eSJR>r&9)Ix_*p>M4qN8pve_W9f(t!jkc1JP}-GhNa4cB1#B@`PLa-(ZD!` zLP{YJl9QA1$!>T=7E5sT^zcnXw7BBImjO2m;!VXjLl zL=Os)>_T*-5Q%zaJsUj@LY{*6|MIv^1Qq*t4h8}+O79mVtBj{rCB7!97?IT04 znUDv*s{z0u9Y)*oQ9A%&QD$Ohm&=xKY@59AXNXp2M%8ldI2q3C^2PA2n>o&nEhG1) zSGU|Bm%wMkC7kTqXZ@QS(pEoO!gFZmNnHtW7-ydzQMyz}9m) zVYr3V1rFTiA}3_p8JD8Rl~0SLc}}yfe-D10l$S?=MnI#BNv-Y=(~5!`)S^EOl3avb$8Hf^Wv=H z436`U6@FRPo-Y|KD_+!=n6~$jZdzY|{bsQE2iuYCVy|<-Z-ll8t*w0O$>Y2YbM2T< zOvL-7nWr9>&DA_sKfbiH_knSrQEqg^>5eaQ5x>4IcDIjvXR%e}%(S~RN8ZbnB3xAOvjk4vTDO;{WKr-7+igvTttiIQNNu>zd6c=Kpz z9$~zpaOM zTrr+87B=Ns9*Y{ksJThA-O4QJ(MG3Zb#kAqqVZ{k?gLtfWd^t$)vIH5jyQ5wZh6CS z(nWemGvUU)pM8ezy*zjC9Qj_rx8qZ2n7ZHc+ZSzW$m1?it?HOo!8LE_3Uaq=xpne| z_m+$+NJ`a}{ugH0bRW&>BX%Z+hL&Y_j}|pc{<)^!oVzEt+AmLxKX;!-Xa(?%~!0z+seSwjY zk;2l_R*;iId|zcHs$scl_d(=}SH!{FfHHU8{NnuibP z|0=cJ-gtg=wDx9)%HHHVzw527{0c62?b?Epm4o|LcD1#&nqQ>=%P}!A@mdqHMbp#c zh{0fh(N~)WlGM&Uhea_dDLMK1jsro3*#a{N8vf1QQe#WNu-xE;V)E-TssL`E*Dboo#nGFR!n=JFTY1L#0xM zZEMXSVVatnl+?LEO-)Tp2UpR@-*_ z_Eb%8uM?ZizQ&mIC4vzM1Q&bOF_}y$<=A5K9KRuT+XBxG_LZwnMXg<1RbKw%ns5<5 z)c!fi^6G-D=0~8dc}RG8c==+?R=v?^)A9rby}1oEuzN0|3IsE{>%Kt z##xq`^U}I(;zKX(%TW#1OWNFmzxea~{o)z9KvzKo{!P#V6+&i@FHGG2JLzTAu9v@v z!;KE#nwe+AIvCltqViVcVyhc=!>RoJ!k@+krWaGQ9n3nJspPng)kmHc`;OjL^>Vh9 c9lqYM#dy98< Date: Sat, 22 Oct 2022 17:07:26 +0300 Subject: [PATCH 027/179] Create app-icon.js --- apps/poikkipuinen/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/poikkipuinen/app-icon.js diff --git a/apps/poikkipuinen/app-icon.js b/apps/poikkipuinen/app-icon.js new file mode 100644 index 000000000..d7ddba399 --- /dev/null +++ b/apps/poikkipuinen/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkEogA0/4AKCpNPCxYAB+gtTGJQuOGBAWPGAwuQGAwXamQULkYXGBQUgn4WJ+cCMAwXNiQXV+MBC6swh4XU+cAn4XU+IUBC6kgj4XUIwKnV+EDC6sQl4XU+UBd6q8BC6q8BC6i8CC6i8CC6a8DC6a8DC6a8DC6S8EC6S8EC6S8EC6K8FC6K8FC6C8BIwwXOXgwXQXgwXQkIWHd6IXPp4GBmQWJAAMjAQP0C4wAPC7hgDABwWEGCIuFGCIWGGB4uHGJwVJAFY=")) From 4555662d1617cff28ca7fa5c90e9b6c4f52e4ee4 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 24 Oct 2022 11:07:57 +0300 Subject: [PATCH 028/179] Fixed a bug regarding hours --- apps/poikkipuinen/app.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/poikkipuinen/app.js b/apps/poikkipuinen/app.js index 7db3384bd..ed37cfd97 100644 --- a/apps/poikkipuinen/app.js +++ b/apps/poikkipuinen/app.js @@ -74,9 +74,10 @@ function draw() { // draw hour meter g.drawLine(watch.x - facew, watch.y - faceh, watch.x - facew, watch.y + faceh); var lines = 13; + var lineh = faceh * 2 / (lines - 2); for (var i = 1; i < lines; i++) { var w = 2; - var y = -faceh * 2 / (lines-2) * (i-1) + faceh; + var y = faceh - lineh * (i - 1); if (i % 3 == 0) { // longer line and numbers every 3 @@ -94,9 +95,10 @@ function draw() { g.drawLine(watch.x + facew, watch.y - faceh, watch.x + facew, watch.y + faceh); g.setFontAlign(-1,-1); lines = 60; + lineh = faceh * 2 / (lines - 1); for (i = 0; i < lines; i++) { var mw = 2; - var my = -faceh * 2 / (lines-1) * (i) + faceh; + var my = faceh - lineh * i; if (i % 15 == 0 && i != 0) { // longer line and numbers every 3 @@ -104,6 +106,7 @@ function draw() { g.drawString(i, watch.x + facew + 4, my + watch.y); } + //if (i % 2 == 0 || i == 15 || i == 45) g.drawLine(watch.x + facew, my + watch.y, watch.x + facew - mw, my + watch.y); // get minute y position From a6f23a4053ef458505a44a4117b28cfcf7c85814 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 24 Oct 2022 13:09:19 +0300 Subject: [PATCH 029/179] Fixed hours --- apps/poikkipuinen/app.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/poikkipuinen/app.js b/apps/poikkipuinen/app.js index ed37cfd97..870b365e1 100644 --- a/apps/poikkipuinen/app.js +++ b/apps/poikkipuinen/app.js @@ -88,7 +88,9 @@ function draw() { g.drawLine(watch.x - facew, y + watch.y, watch.x - facew + w, y + watch.y); // get hour y position - if (i == date.getHours() % 12) houry = y; + var hour = date.getHours() % 12; + if (hour == 0) hour = 12; + if (i == hour) houry = y; } // draw minute meter From bda6b87d70e85940b623ac9f4ba5f2f42c7c52ea Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 24 Oct 2022 13:16:10 +0300 Subject: [PATCH 030/179] Update app-icon.js --- apps/henkinen/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/henkinen/app-icon.js b/apps/henkinen/app-icon.js index fd1e32d20..7c82a375d 100644 --- a/apps/henkinen/app-icon.js +++ b/apps/henkinen/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwxH+AH4Az64AIFlgyjEZoxfDqYxaDSowYJDBGg54AGU7osOGRgvQCA4tNGJIwOOA4uRGAyRNFzYwTFzgwILx4uXGApgKFz4wHRspgQL0JgNF9ztgSBwujMBYv/F/4v/F/4v/F6IwiFBRgkE5Iv3GDiOLMEZeLeMReNSMAjLMBYwWERgwhFyRtJFyyNMCBotTFyJwDCZAsODZjDRDFBGYI6waEDZwSSDyAfIBpoxbABItdGRwsiAH4AOA==")) +require("heatshrink").decompress(atob("mEwwkEogA0/4AKCpNPCxYAB+gtTGJQuOGBAWPGAwuQGAwXH+cykc/C6UhgMSkMQiQXKBQsgiYFDmMCMBIIEmAWEDAUDC5nzBwogDMYgXHBoohJC4wuJEQwXG+ALDmUQgMjEYcPC5MhAYXxgAACj4ICVYYXGIwXzCwYABHAUwC5HyEwXwC4pEC+MvC4/xEoUQC4sBHIQlCC4vwIxBIEGYQXFmJKCC45ECfQQXIRoiRGC5EiOxB4EBwQXdI653XU67XX+QJCPAwrC+JKCC4v/gZIIHIUwCAQXGkIDCSIg4C/8SC5PwEwX/mUQgMjAwXzJQQXH+ZICAA8wEYYXGBgoAEEQoXHGBIhFC44OBcgQADmIgFC5H/kAYEmMCBooXDp4KFkMBiUhiCjDAAX0C5RjBmUjPo4XMABQXEMAwALCwgwRFwowRCwwwPFw4xOCpIArA")) From d2d36d33b8839471072c8989005a3c3a2160a8d8 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 24 Oct 2022 13:16:28 +0300 Subject: [PATCH 031/179] Update app.png --- apps/henkinen/app.png | Bin 5730 -> 2952 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/henkinen/app.png b/apps/henkinen/app.png index 6ac3f151f052aa624e66a244ed1aaed6c84ea41a..575ecbcd4862e30d56f28e40a0f9394f67e698b2 100644 GIT binary patch delta 1848 zcmZXUc{JPU8pnUJQ@vWI8pc*Ks3HqB6*NTESjQH|(ps_*jUW=G(?39Pmm3BQr(%%ao7fqs3iP2;m-NQGwuH?DnabAvS9VZ8S3%I3)g$cqG&JLB-Jc2Oy zftw-WXORdPJ6-ZC#((h{m>CiV(>?!L)*6RJQi)U&{!h}err-!jI}-IT`U^=!orEY7 zk`zh~x6w^7!Qly^G!j+!eAr=vgb$60i3=uTqsi9L&wok8{|Nm_e=Au-<^Hb2ZkH_l zpXTsVWJcxWZYBVLm_&PfkN+D701UHf*^_5dJi*)o#J(C&bmg` zO*3cT=rvmlKLJ`uXNbaZypfL?xms|mhM!6+R9=Q8rOhrf_01-lUI*Oa?^_{fVFIjX7Cesr*#gvrP|ITe;mvdj!hU4wU|tX#wOrWGaV?%o?c9 z8La6LQ-VfZJ-HLz*V9e11AoXLHW*~N-zM&zE5K(sT~{nvC5lNrX1TXu^A@wAd}ITsSRiDwvQzAC5jTQwb$v2tJ190knm%? zMxaf0Rm=8Rdn3?dHcvS^rO~dIq>zM?vfI8ISpk{MHeTQH)ZZbi&qRMiha@%vVoC6p z#)PZx)T~50s_T}gwHqJUb=f+Zgzx@Ulwt);$|bLE&1M<6ygFd+pMc)77Kp@*9-GEb z(>#THdmvl-zYS47P#DoA(D#%7fM%g3nma;4}U>=WU1_9Jq) zS5r`VsbS{DvXRBxrPe0BhTiBxl;Fg@Xk5r-eO6HPX)#~2iL^WR~0O7 z{$!Xj*Kk^uVa#`Pfo?Q)8ne zfDJTO#Ws#=5)G8oVH|h9uWiLZsbPj*^aC&Mg%WR1O`Nld7t#+jz9Hy*(^es_x+N zcxscIa8Y5q;g_=w%P^8Wxc>gSDopOS#&lCS zZ4;kVvqbsL%+GhdneV+MZ`D^cxx#4b(;)IW4YeE}%nkb0LaM3&!gfk~6?(0ears*7 z<-64nzRSv|A}&vou!iucA~4ws~!2B)-yf_p{lKA7B6Lj=eDTTXy^k2^!+UX>5> zrX6K#VL`4w;3(5}>XhEmDaI*pn}yMdiDL7nU8iF=@8>3Qg^PDCN;bbhonxlBZoYl{ zwpX}FkeHCzR#AC0BFaQ0t!Vj~279N!zhZanAaN{IU1@BnlwSPx8QE=K=H7Qz!G!&G zIycS}wruID^?Ob5!a)llE+Li)mNvXoraT^WKamNykFqFHzy7jlP5TST1_z_?5GHqc Pa{wm?_X{u3A<2ILd;U|- delta 4659 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 From 5c077c490beb3534206d1f2cd5c03fa29615e80e Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 24 Oct 2022 13:18:29 +0300 Subject: [PATCH 032/179] Changed color scheme to follow bangle.js theme --- apps/henkinen/app.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/henkinen/app.js b/apps/henkinen/app.js index 1207b5686..c3a2f7f4c 100644 --- a/apps/henkinen/app.js +++ b/apps/henkinen/app.js @@ -10,13 +10,13 @@ const breath = { x:0, y:0, w:0, h:0, size: 60, - bgcolor: {r: 1, g: 0.6, b: 0.3}, - incolor: {r: 1, g: 0.8, b: 0.5}, - keepcolor: {r: 1, g: 0.8, b: 0.5}, - outcolor: {r: 1, g: 0.8, b: 0.5}, + bgcolor: g.theme.bg, + incolor: g.theme.fg, + keepcolor: g.theme.fg, + outcolor: g.theme.fg, font: "Vector", fontsize: 14, - textcolor: {r: 1, g: 1, b: 1}, + textcolor: g.theme.fg, texty: 16, in: 4000, From 87ea7335def0454e4b92cb1c89ead5c0f24c57ce Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 24 Oct 2022 13:26:20 +0300 Subject: [PATCH 033/179] Fixed fonts and colors --- apps/henkinen/app.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/henkinen/app.js b/apps/henkinen/app.js index c3a2f7f4c..d7c7bd5ed 100644 --- a/apps/henkinen/app.js +++ b/apps/henkinen/app.js @@ -4,6 +4,8 @@ // by Jukio Kallio // www.jukiokallio.com +require("FontHaxorNarrow7x17").add(Graphics); + // settings const breath = { theme: "default", @@ -15,9 +17,9 @@ const breath = { keepcolor: g.theme.fg, outcolor: g.theme.fg, - font: "Vector", fontsize: 14, + font: "HaxorNarrow7x17", fontsize: 1, textcolor: g.theme.fg, - texty: 16, + texty: 18, in: 4000, keep: 7000, @@ -61,7 +63,7 @@ function draw() { g.reset(); // Clear the area where we want to draw the time - g.setColor(breath.bgcolor.r, breath.bgcolor.g, breath.bgcolor.b); + g.setColor(breath.bgcolor); g.fillRect(0, 0, breath.w, breath.h); // calculate circle size @@ -69,17 +71,17 @@ function draw() { if (time < breath.in) { // breath in circle = time / breath.in; - g.setColor(breath.incolor.r, breath.incolor.g, breath.incolor.b); + g.setColor(breath.incolor); } else if (time < breath.in + breath.keep) { // keep breath circle = 1; - g.setColor(breath.keepcolor.r, breath.keepcolor.g, breath.keepcolor.b); + g.setColor(breath.keepcolor); } else if (time < breath.in + breath.keep + breath.out) { // breath out circle = ((breath.in + breath.keep + breath.out) - time) / breath.out; - g.setColor(breath.outcolor.r, breath.outcolor.g, breath.outcolor.b); + g.setColor(breath.outcolor); } @@ -87,11 +89,11 @@ function draw() { g.fillCircle(breath.x, breath.y, breath.size * circle); // breath area - g.setColor(breath.textcolor.r, breath.textcolor.g, breath.textcolor.b); + g.setColor(breath.textcolor); g.drawCircle(breath.x, breath.y, breath.size); // draw text - g.setFontAlign(0,0).setFont(breath.font, breath.fontsize).setColor(breath.textcolor.r, breath.textcolor.g, breath.textcolor.b); + g.setFontAlign(0,0).setFont(breath.font, breath.fontsize).setColor(breath.textcolor); if (time < breath.in) { // breath in From 35cb1324f91c8f4e9ff8e3e9efbdb1f05c659cb4 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 24 Oct 2022 13:27:00 +0300 Subject: [PATCH 034/179] Updated screenshot --- apps/henkinen/screenshot1.png | Bin 23611 -> 17968 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/henkinen/screenshot1.png b/apps/henkinen/screenshot1.png index bb6655f6ab41b1c605107503efb672c81a9c33fd..751fc30add2fcca4f373b499287795f974315f38 100644 GIT binary patch literal 17968 zcmeHu1yodTyYI{}NOz}nNP~2@l$7Am-CdHx3?dx@N|zuaD5264LxXe(3Mk#(A#peQ z|Gw}4o%7vw?zv~(yUsf6KWlCF-p~8Izo(z~-Ft>8t^3M2n3R|x5C})*o`Mbt1mOe@ z7W7*H#eH))0R+Ofa*&tTQjwRZ)ADq)b#S%;f$l}UNJWDss}R9YIEtAnWuULZekdeT z%BZ4qg~A`mK9D24$HvD5B@thF8EPl1NX!v%Cx3MfquT)geIVPTK~I>Ls3;zm(1R-+ zj8*>-|11BT%j5pd&CNdR<`1A%?_HY@#t+Eg5)KFnZizHOdgd330oeF5P;7G)ttJ`z zh4xM*Fx!*MnWcUodz_`{n9mc^UDt0{u@o`EpnH^y*e~Utq191<8enwEWFQ%AM8Jjv zDnCgKJyo{_{Fz;`h+2QIUe?QH7Zf235997Q&@+diCJ8Limi`+%63h>Ix3`p^nH0)J z5rb$@y1@`WGjvh#eq=*K@tqvBZ{W#Zx}C7Tfz!`+<1-g_*k>yTAH!kU6Yyv9Oqd4T zA)VI-8P{C?b)Q=VH_Z#8mIypbE-Y}|meu1P@ZosY++`F~(sSzGVUqLt4wfmlv{A^P zq!lD#tE~uzV|>%=#)}Gb#uQc0prR=pwzF1k^?NqwDqEz6>4%X~7o!k8`^yusF&4q)Xv%5A~mE z5I^0^s5?!A)QWz&+G8`2bq*D~FCm#JEu>F_XNsN=A`1hNYPF_-Uxzx=Ic&JDhBuEf zTEOuZ>98W~5)ItG!6>R2ke8xx%1?6cd z9`bUR%?~HEAIEM%>dA2MdsYdSN+MePG6FI5n%DQDmuA}ealK`(Eiz&Sng+;go=8dV znNQyih{*9^afKMW*sr1SF zlR5IH4@fTSrPg5r;U%AGD9;`}-hSvq+A6hgq~=WU2qYdy(=}ij@%|RFHQplbE9z!s zbj0yc0YdU_t>Ltcgy>Mh;_Zz+L8p>C#qOm(Tb`G1C{R%I*HBBSV#W1@Y!lVu;N z`2`~FE)&%tg$-JzZF*#oAj(yw_-FDo6sK8`fG3J65)X>d;w5c|L!Uud+Qee!f>WM2 zn3JaAsmf5maP^<~m=k@)d=x5aE^QBrXz_5z%tA{=3c6Em=icANK7wFjG7LmgwJJfLX)$3&$?H7xX2MEjP_-uAr_l+2&baZ6>mJTNkte!ne3s&5qEYwb zS6Kd0K{9;L!zuG@-_VF*+7wXVCDf2%eQ97XWf;aSlbZj+Ua+33R5_twW!T9c?Hqfn z1N8bSAD>zus+E;7=Pk7kem+qlG>(ot6^`$4okFh4$ffF2kBen1#^j^<&pno!*wnjxZHp82^MYGis|nqTQ4*%39r%5o)hjm7eQgSlO_comHpEzXLJTy%qr*5y`6el}mt*MWez9v%- z?Cc5}nlPS>ur0-+@!}QyNJ0HwpP}n_AeFN%`r%!CU=PNu7UcA%SPbe(5 z2`e1&jIqhI$$inNm#_E!i|N}>;}4vweO@2k*&yAZrNYYe5c=rs=o0*~@aqScj%p`o z&8eoUk2Px5M)nitCu2XlbL`Bl&74BI5Zm~x&vvx7+`lBQc0cO#n4b0P!SLDlCKT5b zHSt!;Zp>mHpvsz3##cIxeHQV`gc93-dKq)xvbc-uSGDgHgM@dT$DES}OB_P8@*mS|I8Vx?j*(2QpWGIQA!a#nY` zbh@=4DApMqYu{JRhj&?eadu^NAr66o*T9)5Vh}ErGsG7JUg*0gVX{+Ca@?s!zh!;T zT4^b3*`IyV;#Su*{cU;~pOZ=A)!kQI52Ww%d7G>@^1iKjS20C)69@s+q6#ZsY^~! zA5L%0^`y&wmXp=QamgqhZq~okKWp=DaFxIv)d@NnCflml%AMH!#`utFRQjXDfkR5j z_~&=r9(lEL(_C|^<0_`s%GPe5gENVeKQb0c3yb=?(Teg&?mT;7mci(f?I`7QKK3a6 z<2!}%#GTA$v1Vmj_L(vn;$-4D)LXj?m!TuFXN~*87BUukbDtbkMsd|AGP$#ZEy71* zI|OowpORdP5aqI`edF)-9KSF)vGcNZOMlYWlQzmf5wIOvmwnK>vX!NoohxuXVL36s zKR+?U95PXfbZ%)t#cRg9ZmL%Jq+sf4^>U_FBW71INzod2>Da56`w>@#>1tCc{#;YFS+&OX7w6GP67k-n&oQ5Gmr>Vz2qtmTTPvA(Tl7xK zXiodR1CCFer-ri41DgfI%&OjrU}IKO-_kp^jynOPM==x4-|42^{jG*N>osgMKMOtn z%K0tGOYJn}-0{kF*xrU%9;cQP_eUVlpY zl3(?Cvh2IVC!Q^gZ=AA-&*ZM18JHh-t_(kBUm# z;#}>SQ99REdvynA>AS~TYRP7!EoMqr9~LT>=1LgDl~ZU6X-(WKuVKUQf7lv$o$S3^ zz%zPXIW5IE*ZyUEuhfN=Q8P!BOY5j5vd7g7+_Ci_J{ayN3tC9coP^P0I2)mPVo=tG9DJ$pD7 z9*Ua=Hn^_EZ8e^->}bqPjrex%JZiFQmcFDvYfEl&xUF)VLs~T0@tpeX>^|VO=2)H; zydX^TikIo>poVEMND?(z+&Hu=ENWd~22Qu`wGKjDx37E6!TrD$jOg%oe~?0p+w-`J zZ*s3&Opl6l@S$41Cof+UD8BxbIZ1|-Sszc9RdeX7y9*a0L%# zl}kC5grN`K%Jg~QUF|ZbvK#ki@TJ+(sSDl%0zbIh&k*o!zsN4^ADSA#Q%AH7OvP41 z19S(tMh8K`lps{#3Je@lV5+}g15W@TlwWiR2o&J}g8spCA2{E9o&m?roZn}Zq;L=# za7PFnetD3;aYH!sQ2u_+0*rxVb>&r5fU~ZZr;UxPm%W>JS4;Dad<^${23{Z#Df7(% zR?%VF1@Olm9>Ba|8tP(JZZ6yw)^3(I+*O=gP)Bv zOu@kg@EIUON>ETp;urtF8~KOC-!t{RY&_-NT!4w*QvY!JACvz)_-`lv5^3;fk-UEv z`KOUTW=infSpFwZ{C4v%D&S`+ObMR9$4m;dQgcBB2qU$Fg60F@3?$jj2TTO~Vf%f) zxu!ftRkwc%oZD3tWFPo}H^0w$9#_ZR8d|*K5%ZaHKzlOynz@ky8qFFq&d;1AmT=E< zzJGh>I_UBsH3S`>P6iGFL*h`c^egV(?;86}KwP711SD=Ba**flgwv!6uchLw_T~ zLpy|jiHD+Bl4(^`CUiqFej}j9xZS7)u-WtEnLFH0#31~QfJr*@n@%@mD$_C|#X!XL z8-bX!>9-m(d5!SU!p90M_kJS)hM@cw_m?4mMFa%?zf7%6%!|vDncl`T>FbM+(^(p6 zAVeUPnDazr{VCEDsDmX20Skx`klxktGrc>UdFJ0lAMe~Zmjt8s2BfF&Ekk@sC^@eD zZB~3|E@3~7wW#@ouC0iM_keIb_s z^-_SpEfp(EGVI}n?)@6{bYHdhAoL6FJoB^f-89hGm?9EI`@vJ92W|!zNit4Ay>9ra zyP|<3>>hva+vtzGH>(TiQ52fP%8M`J$$L&T2&zy?rp|;~Q2tHjK~ndje$uivvv|P) zC3;>$t%_LhN`g}@r0fa3d2-j%S0?n)uZA)$AABxMuecGpxOYRg>(pvPq?-^|6zOx5 zfD5V)1b(tWaNn}XN{HahAfKFu|BwSFDE66pR>RvItKF}!9;4h?QUzG#v|@LR3X!H! z@URa#kD?5YhcxBBnX`jT0Amwd5_M5<6uaa+*2dR6c7*R-YlyTeoXP6Qq&Q}gq8!Ut zY_mUsIV|obGA*9p2a(r_6+QwKdX$(pqzl1~D_V@(m^#40 zKLyzLKP8F_5xCns6MDBz9Bv6>cRZiO0Gg7brQAnUYTS=ck3v%6Zb#fImkqK2cQ|ol z8#_1x$<8e-%{FWF7=LDH3kdrb1K-PU5M0E!*7IgHWKBTotKc6%1N4`V{xSCuQM>oE zJUDpCQ{D?a<8=U6cZ-IH+F-uD{|V#k>?dYRsa*8a9O>bM%@ROIy<~wMU5L=BuCc2t z_iUgm?Xxuv0<8*li!W=s5D&%#uU)&mH*+h(7^llK&tLme0J8JDXpepn}iA(R|J2c zR|VW$IDIRV-rOqZWy#d5mu1wunOfLT=dJ|5+8jYCt-MgkEA^Y1j;o`cB%o%Ja0 zvJ@V7U_{!?#H)v_&;0!MfC>niFx~pRDVS=dF(-i0T>)7yp1+vG3V1c1Q0J9aHKm1H*P~?+@FOF*bL4FRNqWRSjo!R1^JR%9L=ZCW7WYxR z378SIGhdSob@od(_fgA}L7sET2(>2w0&Y9pon|&q{-mZO4LwJPO+5ba)rJK##Uv?s zSJK59Z=Nax$pqdA0Q3qW2ISr=nBxXhO_?N}(+?>l>$j6TxCOK;Hj}*f0w?>TTX2+T zWx*SlvKMjT`W4Q^kCxs}BJWhiDb5-IRD)|1rH6m;BL5xl@#e!Shknv=X~Y%e7%22o zF?rP9k{-dVnz#}Rw$}=IFr<_gcGIvsW=dRZ&Si;E2~ZKNLuN>+A?X4=yEo9cSl;s+Y%rGjvaePBRvlw~=}2+tru0s?$G8z2 z%(jPnvK+^1cvd|Vi3N~(&^_ik{@}*>SKMRe8kR3B)L$T3AjgFop;CJpm?=asx5h7> zyW`f4WC$PBO|=bMVW(xx6oU^~M^08SHcnmUiYWMFhvYoXhS#A>&~YQTD!v9mgB?Y4 z6Y$TG`fvRib)hyXn{t8 zE9-bD`h^iPcuD+p(06xmLYnOuzhd>I`aD=pDq>EwXFoh+o?fLeHKHLNqi$MJ+3kcx z*yQeV9X|eW{2Kb>j`{6Crw`4|sUdCqpN5^bD~8O73d!gzO5u;4r&h0ZDjFmLV}34y z10^9;SYKz3G0j@`_ZzrYQ_(h$(49HWL#8-_PXq6=I;H9$lB7*?cps<-s~^ z-Dr24ZCy~4wp23`YwAr-m}zjE<+s{EyQE4P-=ogW>Ij%#*YNF}o;frX_|ZWxBwuBh z>tWK}Xs7hhw$QvTe|(n$tI~oERX4hh47=tKAGfS70GOKCCdzp)?fPSu9kjVA zr_Cq%Mq6AmFrm(IsNJaY?SjmskliTxQ(;ab4?ABM`T^3i9cf!b>3V_!cpI1FyPsah zy8I@>T_JZw(wK<*`AQjtADR=vWoX9pj?ZEKiQ7eFArQePqHd^9vDz+@zj4ed`W6q zz>BNSyzDdksD_hn7PNU=$Jlp&J$J%B9N013KM=xt?=RyJz*j!D=&21xGryjluTOq> z-Jm4!0N5C2)EGqeqo|I?_!qLI#$bwoexi|0WH+3z2xhztwRtsK(Le7*{@GlWuN?4~ zDcvmZ=50&k1OWbF&dX5dn7hr@vl(d5Uy~iEYH*ve+(@_o&ki37Hl}G`f6JJ|21m?c ze;NE4>!hoc8>oMhXI@Nt?Jj|}EsqTCvQk2AqsV^=Z>z9iGt-R*SR@4~`&C=`M;yM| zwg_S~Yp~ls&oFjn092&#HqPWF$8>IB`Wd)gkfR`nV#$CV_TgTe6V_V`HV0L{0>FV@;0TLBJi0Oi zilaWZLDiNdMM_g67>@i|hE8AM3U+@{r9{u>4S&nTV$8l~u^6=`t~Gr|Z;om9hXy3JJPVPI^Vb(I%tBequs=FD?) z708J;=vy_*1vmzSQ9R;$=l@xe{~iz_I5d~J*-^v3MDFI}th5v2*8$fBjCWx1sw6XZ zV3H?AbNL~To+{=ga1^gQJ2lx|M+4VJ`J~McDk>xA2324(AsG*@Sk52DJ8?pA`_A3y z%6zYmu9TG@R8YUTQ#+W?E+ZwP&^JHJ=*s9G14lU^?d;8Nui}a6jn$=n06bqbju$`m z?04zZ<%^-X+(<@h0)fl5b_~8f(ZuQ4mk^(CE_z4LJ@=^&JjgvVt)oSGT4|OP9I?n1 zn<^gVWJa1wQ6%xkJiRrbR2OS0W6DHR@%q#G7#>0sN}ZOwY7!{4jdD>=F%SS0o7%Bl zGwEm4N~+sYSHh3pazIj1snb%|xTVQYz*qmxaac7K4>ZsBI1#|(-r%>^>n-VRj6SD- z@=sQHH{1ZBJ(-OhR%ysHq4X)9n=#8Hq>s1Nc$Y10_~Y+ci%-Z{!f`MxF!{2 zMY!4GT5$a2@9sC=PJDv7EVx{t zP0Y!d9V&#C4-&;8=)bW~4P8XS$uc?+^?>qV7|4vo`?8s++VH<64l|TGN06_hG1Ncq z%$^vv_g+z6e<+*GeR+k0o3=}MlUHf;rY#MfL3g8p^;LJsR+gBqh(6!{ra@o;hHI$* zW%ggu{wvA<`_#4sIm0>L&2Gozrt?Anlb!Fb@!?I^sU!sU23-UvXu!(uuK;X2{dXtl z-*hD`9~Dp~A_3%OkGGoJv4M~SO{Sd?{T9#WwIy1v=e^#kw_}%6#rNp`(G@j;t{ChM zG#BmS(4U;o|K8XD5kTi6IDrD4OIca__vS&4{cp_&Xxu<|q4xOyGX0DU_-gC=Iz8&H zHt@9<%FXv#Thm)*OzdS(=X6g(h6M%1GLl|=>JGz}>K6!MN#gAceh5-){BpT*l6!rb zd+j1SJ5g>HvO(8tMl64u;ov2fN<2~?G7uI4;wb7803WE@C$|P)5`sl zyPQ#8zWmr5DI*PuUk~P-v5B^WEbrXw59zAtvokdwR$|Xj-)Gp*{g9`Ke=37~dIlbX zPwY`6LqM}=>=Y?zy8)V2+5to^y<}%K{lsxdatL=HpYe=M+zROGzctJigCpN#4=hs+ zBy*kqRqctxd;OS+FBB;c8L&d8*s$iBIcci={FhiE@))&D5%ZU665EdrgW3fJ;TGx9 zKQAqXJ_kw(%qVf$mN{`jjgy?35r4+Wyr^~<$0Rr_FKu71A#hh2cqp;$d$Dp*ZjxwG z%q%E6a4Q4*!lthKdg((yfevq(*z;i|M&V7Hu06yqFbS(IaI$C!#P z$%cqKIC72e3Nz!k9c91U>~$xPwU7ZMNXdvG>U z)?G1{ltFEWqH)W#&UmcQGnyBArGo4@)#OyWwb1msmk^_b)CN|<+mH7Fu`Ez-z_+eL z#B&Ql2qv?N>buyhEnnl$4cUsuR^uw}@emrao_*1)XmY0rU4AwfY8-pr{=u4e+o_&2 zG0#yuybyDAk}lJM>w08eJ5?vv1IhqSwRrXZSajR0{@s`SM?Nz|ZkrJr56^FSPAnMUzqGOhH4YC926+sQ*lWg_zO{szMmb+iu}m4~ zNiQkJ9hd7rWkjz9DQi8>5!lwClw1)NM``2FJZ(F2u8jb(swYrtzy=7Z2;C`M**@nc z&Hs2coI~08Hrm2p*{;o3X!;+5m~RAO(wwlw9gnS==wbJYi%~UwoC9>#P|+?2a+{fM z7BX$tUVD43s@b%hgrBoqLFn40&4qhN&0o7b^B! zY?2V1Y8uriwcs%`>~!0tsW{ByEPRs1%eh@6>s3n{{>o5Ss z8p2)QgB0f`J0YVH4>frfZD9avoJbO~$ze+9ay)YQZC9*dwIzhhBF@ zL&3*0aVifl#GT$4G5z}lLh0}rSN`4j-i}Mfu6T2@SC%kRnVqUvabIH=rTp_>|9s$M z$IM+rUEd|CIQmi028KI6s3ZYvkXzFpm5ZEHff~Ce%ix)^Y_n(JhD(Y_w(*nib{`7O z->Y}>RMwbyVE*Nrz`gD=q5a$S?Gs`Ryovn;c=MpE?9nx|x$g26Zhljpc=k*-qr23> zFh}R5+{|$0%F>A@Z23KHeG-ls@y`CD_RLZT69@8Xiu#cBRy)8Van8@FQdudRjBa4h zxNd~bcfkxMn@pV*${{_$dMr#@^8RjkA;H(OIic0E&#|Q(>r#&j4?cdX9hj)7ep1V` zYO3aPEfQ`M5?6AkQuZxxAy#yKkyDwMJa^fEjPQN36V&hj35*PmN`uVA!c6>Tgm?dA z`)<@Du-3@LUginTB5}Hf%A2=wnOb9=Df7ZZB1fn0sbBU8gTMTGRcuB-9ZcBvp;2KA zb+UG=??Zp&j7;?psiTDt=L&2qKTrFA-b!-3P=;O4)ml$Z*7iWNhwfk4vT#mRhB204 zOjNb(Q62X$USMAkrG(W_)?z5qOzT|O-s1U^^9v`f3@|QCP4?6;fD;= zSceANM_8PJ*hZZ)#gj7vWM}U~2HuPNT)RzR_bN_Kt&&BR>OqqT-Q$@_s`I(R3n4lw z_*9ZHN#`=NrT}M5)%8Jn$QfRjNq%!&aMaMG0v#WC1!n0XUAdfF5d?a^Ruz|{qR~j_ z&I(@nnq7Zg;}pKcu;p?X(>{I&qJkmPm4s zS=ye|E)GgUFUEm#)6F*2%PdBdQlwzsqmZWtQRsakf{0>>lzXmEPLi~ZsB&5~w9&nM zV<_AKzJRs*p~=f>SA`+xpjm1W zSR#2r;WnVLQ5`Yz`?~6l=!>kg#-GbQoFcH*INpct;f9ChJ7OT(Fho*u$=qemuzNvo ziVD4XvtFkK5OixI>zC>G8ZsYV87qyF0fL;IRUf|{Z9$BrR4_|^LDp#+{P^vt1g$}UH28kFoe=o6vJ$39x?+%QbP+T$#Pek|aQG4$A&MlrNM(T5 za}B1^x+FpZdnR);VF=Mx8mMib{3SFOUF542!9FeG0R8L4io>IT zjvH`Vt>!0Npv32qGK}D#^#p0VT|hhNLT9$8pMB=^l9?3Ii2k)XaLvO=5WCkUnrC|g zQ3C_@GVa3Rmp?%{#R(X^oCyS~Lvl#Ogq#{DB#@vY z<7;Lz!l*3zX2+p2qz>7uI9z#|zF6ub0RFjcdo;M3Z6PXO^tQy?-ITe;R+!#=#)Tn_ zKN>KAfs#j`z}>x!!R>n{##dkAw;@V9*u4~DCPszwhlXo{QV95^Aov4wJ%Kr_{^fH( z6}0tVs$4@idCXc>0EpzV`U-ut^{4qx{*>UKPLz&VK7iZ3;cOk$kUjS}j&tEC2Ao0k z3nufO3v0_o2_WG9874;WY zs35q@!tM?ADe%W0rH2kwcCZoEKs&3wXYtUBVz!aptSGpf6wqP)mEpk7r|Z)Kx=2Gp zvU&?1@N<^ikh_=UfRcPV?3Lm0wolbnUU7gdF7~649v{yqgjSVtqblw+ zr~Jj$dM8E7+ok3rf3yop!@NCFk+B3nm* z?8p}N4FPxaK_eNfzygQckTH+F&w}?_)IldmXQw{t2gC^jAe819{Tj%^M5CGPPX}9D z@8TyP(IYE1^TWhah}<1GQ)ee3L4gyh<$Jdv*lH-8FMSEwOjr`bL)rkxP-C11-$W}& z6K-*qlbxQ5?>=YDaF{3bSo#T4HIN1{5aBU^^u zRGBrM{i6Kl$Pww&TO(@kS~`G$bU@+YHEx>B1UURwDOdjayRoqGGrZ4lW1|0DlW6 zM*zIT&Ua$2wv(Va8B^5r1(J1p#Hfaf@J$`I)wioKVuzrU*fZbhJ~?w{z-`Qrofvl` z;Jsc~cJQ;HWqpNNcEA93*#iQbf%)#lR&N^8C>eUIWSBSnP6#OR%hCCzVrw(!IuvL{E&E@;{{e(d7!$EBy zK=sUn%tHZ*)t$L&%XUke0U`V+cFaonGXJn4?})+Wzam&CsNc`IWZ4WWUUXslR6`YTS7(~Yk8|pYI4`IDt~x%c_?qR|y&Qtt zY*3r$PqMsg7RcUyRH_cU3VV~S#Io~$2|+5ptFADMPpb2Ir`5ozaWqd{SKVG6OA`yr za_pdoD|JF+*B-f9bkv^UV5z88P@h=|YiFvZCG8;k^nJKR-6hsg2oYjj?KSc3E-P?h z3`b{I+K68tMXuUj;hu=F)I|G4dwbTN=s?`U`x6n`1vNgtrsX<8yV!&?wWIb^9reBi z3d9t!A*l%gpSv*(1@t_hU-0A1^Y-XCCD)})5MA(MZ@Npn(z%jxnvs?!Ak|gpA#qIG zWfjEE(m5e<;~2h>;+z`|{UsRP#eqhA%p-HH0py^rzvfKC}#vT^1F+0!Xe(cx$0(`0|m65^CIeyW2b=X6v06I@w6g=N}7U73I-=uLf2Gt1D1j$^;>9g$`Bj^~|fO2vY98aX=Z#nmwR z{^{}4k$R7Y|8P#;|KmA+dN~hvib;(xQy{2-kP4TSt(0RN);~8qc#diMqR94pMw;nkNdqT697ad( zBTH%oHn0|9-&wby{FOmwlx{B8zXhvaRu8zu@sv_^{fjU)au<$E6ox)rDmJKLdHv8# zbKFp`Eiyx`kzD!DRi4D&k=kiQW$;_DPIIZ3(Sq7W=ia{vV!2wepl0zbfOxwVrlv6~85M!l0DaC?+c4Jz{kLh+ZvDD9W#eO|PR)~^ z_$w9Xy*7YQ*6OeQ3cpTvCqeB~AZ21k&Nt=qCJM(giXH?x}V6ITDm3P=@=D{>;Q&b?FPkNWJISvLU298z7UBDA?y zIpjbc1_ims@$|F&lv4dNJ2nC6Wu<$30DPBIj+G0aCN{}#J*}_nfy(DDc_dSHN zZ-tC~=YPig^ZEY1+yA=0xw@w7dCnZ?-e329?z{YO%F<#=-cZ5~H6}P3PC-GzbX8sX zCItl*iu{+J4m?rxD4hPpJ9112l|oHH10GQR^O}M}K}YH8Rq#N^!s-6~N6yyvkHwxn z8!HfGxL2~_GQ^e;V_zY|06G^;dF zzw+v1gg>?ZJEy~S=y#>?fj;-p1VFIQ{^le&mow z%A^~kfbEgyvm{YW$C6fFEaclMXP=yzXdYps^yTWJK1f0PP-9#?vDR1-^>9jy6zv)q ziPCE<1KC9&Y2N)jlL0xn;c0{Yl&Y)2i+SqOAjRc->I-++ncIyxlV+F&vya<7C)4Rq zrVHz>ze&KdR-r^V8CYp$Q(%1*m@yyjiQqghpCCS)0A*fnKP2BHzDYg&|KZzm zOt6pj-yu>=u!z~>EoU0QYwlar4n9iDwcmmjqbNT34647t&QZ!{9C3yj?=?*=j=IV( z01sU`t1YQGM+44AJ~gQcX{Xe^_Yz8%QNG|35h77*c>RYbA5Ryx$3HvPK0?wm(b9#A znjRCswnZW5gT$-@<*2aH=*JvKETxYT9I!a>-1MpG00EnHEHqt)M%j5FC|xFi!7e?X z-@)f!+z;dKmqmrqh|spF`Y9_Q=M*F;V7Rg1t?_f*DMWP$&8w{*qZj&_MNtSGj(qH3 zHE(^+u$eb9)4aByj^t@x^M97-|0Yhb5l?)nB>1?lf29xOON}8NNsh3W{}&<>1bohz zO0o*TfmAXnaaEM~I;6=q1(Qk-eW+q;*|nGm=F18~bIRmn%dFH65yUH}&LFj)8S$I9 zi?Fk8B+=8a`EdQSWB#y`f|9R-`7sXa2v)$dF>1A^K0$u=LoX%N0&92A;K+smp6he} zkU)hADNUS#kd)m&3&+nO&1!}|&d>vO!XNQqBKQe1kdN{@WkD2=HW12xSX&Fs8v9aJ z9mP6*JM}?87XvsO`PAc4-2FkR+o!eML+&h~S?q#JV)HkZ%SqPMmDq~ z(V_6!o>&xvDLgiUCe)9s>&P<57Ow{^K1y6M^#wMM^*(>V4RAJXvfW1R=02b2p@Q33M-8$y7q3mb$kg6Rtm>IV6=0Kl`YDs7+|V+mjHwQG-)yn*Wo z_VWkN`(Z9jffLOy+**|6#a$nQkJx;dOlc~hPDhd>Zkhd3BC1p9R6P(-M**RbErZ%S zgu7ye5*_xAg*8yw{S}sz_p#rNu28Z)yG;c{g+y!bW*x576Q!zk@n#nV7i3wOf&Kim zqghd~Ul5gl9ft@V`ZVBK73}#A1rzP)m(zC7;lZ0azywej@H}5G-wun?3aZoLqDn2X ztJUGE2`JQQX93y-9Z9YpInM=Gp^Bxl2$^5bvpX4f^ zH#f9^!*Jn$^Z*x?TL2gJkGOcl99TujMGuiy+iSb*k%zm<>%uN^Rxk)_m;YpQmw`&Jk_CVumTEqf{e6hw&k|uOTMj$62i=(ByLxEPsCra;XM%WeO3 z8S%KWd>L2*|AxeNs<`E}sl`K+PLFcKfuA0KPXczndz<7VW#e=p&3Y@(91^H-t{ZqZ zDL3J4lGo_#IB{UhCiEZ94F#QE+Y0fX>F=D(nB)v(+)2KBs5WsIxL;uqYOwdF3P(%( zTR!X<7KGn!Tb@mxQju)s(Hb?()LQe`ddY6fT)BS%>LCam6Gvo*PU8s70;JaZ{cPdu zbFlp`g7tC=aZ63%9e+?J_VuK^!iy?lc2_if;s!qt8aMx(OUpeLGVl4>Z)wJ2mrtMOMw>c!Y0$o-P_RooXBQdL*{u}0{ADUSBwbMO!++gjxQk0vk@MCe^)IWa{ zZLqoH;Ys)z!(;k4?jgicaDP>v6TzugKx2yj1|q0mFU)ns1x=tk=C&<5>V2k_$=WPp zjWu_~dgL+%c0cwUZjXJ;@6td!m|8E8 zxuHI81LxLi@#bGB(FR%q^6f2_12;;DmMU06dQUxghu=eA2gzUm7QiEicRml!RC|5r zDC75vIfm(m%k$2oA=hG987JG(rD#7BY&~rgK z6W=1JnF49XBoDlN>02u~N-Rm6Q9+6ZT{y#9;@pcMzU2m}>GtCyM?e|H&xYh6zVnCX zQ}NZKzy|LtC^<3(rvff}X)HG`Ub5JTP(R6j&o$5BVKmRhOk)6ny>5}io9h-YFsEOq z#-vJCOXAna5+aZ#q`aX7OmVb{@@G%vb{0c5B?5JijJzCzk0P~0|1Fh>Y#V6yos0%@ zqKaueSvAIz&={ZJ3GCZf?Q&c5#j;4~o#Qe|k%Zf$wlizZ$qOwl!q7T@Ykv%xK2;}7w zbsDMT-MWEy^OT*yc2n)xvt5?%T5DcTR*q< zfS;s^{YFY{`N2h*u{;Uep9NQ_{P;--;J^7y0aan6^TQPYz<~2*P>?~cf@CM-l zs~Iv-u;mJ-N;)n7030-ubQanRjig?wDrRaf>DW99@wT<5xb7#P77|u)5~`ppyKkGS=r!&w><1 zig$>FbIDjt)8^YG4I11>R{L00y+F)Yq&!CTDI&Bl=xM}_OA$PQ-6NkrR5yR} zOsiIym7L$q8&A7FCa=VMO`g7!&D@^1bF>nz1%IO3^e&>$)?*`=ox5stfxTVr@<$D> zc3}ez)O4}kBqM3LqT0jGS|hw5`-3|rY_Gbc04fMTo*z3@o7De9%cSx-=oKeS3#Y;} zkvNl(zIkxE;mkX6)W#uSnS)t1x4`kAnqeAS#BQjYnu(Sv(6RxEP~ln8K*Os^e_Td4 zKFr+UW@`HRGn|-vM_!<6%l{8X*6T1bCqP}!Gz@MofzYMiSa-sND|kd4pETg@$XR-| z4V`}@+<(4pz7OY6{-6c5%}+B)g*47>2-bXUKqIaTpWq3eUYYi_dZ3i$IObu46*$i9 zH%agACLt$|k|x0z&-{!TcG{l!(P)b)Htr>ei<~fKG`}F8Fp$xWo9w2+Gbo4%f^KdbCc2W?5cMJKc-=lz!@fpW6YyAk z8~zu?>};Z5YpFq=>-hXxjSO+rnZ7rkEwy4>25dE8O)~rCEyG%?!m@;Q5B7?S=&<7l zc*dlva>em-{7$iJdAJFrBQn01=)AVKGP6|w3m9Q$v=0Wre8a19;;r0CSPtkBE2$(A z=}F^6HM;hNYOixT5_wJwoEg*zoX$3J(}>)lD2ihhj$o%{LQE&Td_g~=A2pC^^FV-k_Pd|%qys-1+f(!(x zOj?PRa0Ku;F~~1SQM~It3ogsl!`-8QTRL*5Dv(TH8xME!N#X@wbE#iVrcV4*8;md1-B<2||Hbwdf#4 zh4T&7thh-UY(>34!AvFS|@htkic*0ERKJViIf z+>^{Sd(#!L(@=swOhfyJ-oki%l-^*)G>rrkezmH~BLx<&zT^9&o z)&F$kFM*y8{(CA=yyaBD$m+2<3!UxT@&~`r@Is8N(-o-`5RCK6?qv_m;FT9?HfW_z zpOc;0-n+Y3XirR@kQ=S!A1Dj+Hagc{IYP{5F=VK6`PH2_(9ltVfQ+6Ur$J|A8&Bl& zAe`uvm-@@v=H~_qd-iOwFCEfgKc|dWFYP@!C4LL;guwqq)tO^zW<4j3NAb#)xvyqS z0K!dWH)gyH*=hdnS#`53(4LrUPj+;?z2Rf+=vyo76!Mo^d!~{k)B5rplS)fBDdAFi z4X4W3$ll3xqW(Da{@2~v?x#F0d+bRWlAP){@E?uO4TY4u8F*Haodp)xApcUXMm#uJJiv)l%N2mgy{Bd*s-&`^7xD6{F9A! z>(zU5CME!O5VZqLqnj%bVi5de5EH_IW6VT_=|AlYlF*ADsfBMfq>xX>W}b>MxEr01 z4n4K<#ZQ+O_p^=YZ?eAe{^Onq41y5((B*5{ja~)oR9Dt;Oo0JWiXP6q zD#4kxKC}Q_WRHfRvZCc5TUP$>HE;v9f%3rRkHg$>Vz? zlcz5h61!feHd<~|uh#A%;**OQ!j}{8H_&VFwb*m$$vYIkqCUvm8h1z}%QDE}IU{7X z%gH5$hD|d7#Q1=tyv)*Y{TS>>)c*2bz7Hy;TY?ocWyUFBXm}sRZczUi@WvmkuYdX4 z>$#ZGx?O(%1J-eQrn9&hKJzW8=?Rf=3iE+Z4i{|-a`oAvv+q3lnSFL-xj-}I#HcVq^5FO zn~LxCy+?6eObhRq(upq|wAF=#-_035k#nFt_B)w+RpyQw9K@iQv*M@{9?Wr^YL+S^ z43|w>Yte>^N&D|pLYdRNcuQY&cGHc|?Lv%)Lj>!q-4+FVz6LI08m&Jop4TLoQ%l=6 zR9!P~K2q9PKP3*67MtzWNbG8)j26ghzLipK>5!&pOJ|(doNcg9b=cS=?%@6)UCS%C z<~s39@txO_HI$-mx$0Fx@QOXJ0k7xY7nxL^a|GT}s4}xfsO^vEZnASj``fcds|LTF zLAGGHrfhdbZNTs1)5@YmRA41p(5*kRKfXo;U&SeJzQ?X2ah;#PgI%5WziP%Ak4Nxf z?GM6x3EBBq9VOnX{j&m`kLBP3vhzhMeG5={GJ;C=o$0V&D+~Fnp*_RxKz7I9laV^7 ztE;X)fZ~P+(w43Al%FF!X;3tvFg`rm_c>@a>vF+Hz4dCMqa5&7smbKTh;#AVdFNe^ zV)vW!;xZ0C{s5W|oedt}Yl;8pE;}S+l?YN8)}Kbc5_jy4M zibHB)-am#n6?Yb^WXj!+gWT)PY_3;Jn$MeC=|tvZ9EU0mTD5^A9uHohDy9fp8}=m| zGf6y{MP1!jCj_f33upNjucX&7TIT0G;HF-ADmI41inWN~JYgVc+5nOauQfIX2`*^(<0M2#AFl81l_YOYDJez$*rX{7 zl-$`q^DaIGWW7u({S-`rKKZUrX}f#>fQ!#QcDRwD4(rJz-U!J~OS$YP7F-KNW+rjD ztH##G#|(uPcOXDn!Z*_y16(iRUCh`SBNA8<_`0{IKTXxku>7k_C$4N?H+pM|$%QHUqa z{H@9dDOG2gaQAML+I1AbiVrV(Oedn>zj!2&!9Igfp|%(=Ou1;MIr3Q>)d7G3yITFN zFZoqw+KBF_=Uet*NmeD!dP|_TopG{@ATuUE$wR=#K09%J?a=U$n*CctXE{z4iaV@Y zeMc-_8QluGcn@eZUh2+PRihk}XciaU#mC~Pozp4fUA)GCAiN~B1;6TG=5+V##uI0~ zxteXaOT5-<9!J&aPhOi($H4sX8 zKp~$DP$IvH#2+S$Lfq&ufj46Ek1|&~_`|#$NF&eyj!6Zq{z zN_pACTlk_{XYH=*@-GS0%5yKbtlc%g+Tt2X%=x>!9^xGf#HMbuB_BU<&Gtiy7wuN) zYUU{g2o#aVh#vjK1%l;u8>!hpU`d@s$1?64b+ zBgvj?dmsd^`%uFLSQuS7 zRliz>YsGh7j%3d(=%^&QgR91PWdn}uZ!{IP0~Xq&muDLoxVO3-7CCdf|Af3rPiq$& z^RmV+^fHxGbEq_p$UrC4O>c^9(ngoLC9#)3U7y=7cRMAETpB3mL;#tOL>+}8`f$9K zU~S{)!aTLfHm)$tsSN~{OpPoM&j!KzY}o{1lQ1{Dj=MvACdb{{U%|Eb%^K_U82b*m zWrq}Ca%E@V4JW9su3ni@QgZZVR*pgO1yO6P8t8|7#dmamx?Yp7P|VNDfAgc@KI`DRzp(4Q$!-1 zVA2$wLj=^PN6=02m)z0b*p1cDF`L|;IR{F4>Y^rR#uDnv=iieuDaks_V?fO<&Xd$BlKa4F3c#nC2|D8} zX*-=8ORH{B(Dz+u{AIl734z{0jnp6*3@83%JOh8sP)%{inIcIX)hy=LLOr?Hgo{L9 zSYog4&cB}I3QntBwGg*6$2eFuFueQin!l=26iP)&wB(a^)#)mf!((roNf`&<3$z3j zDBvBC6w2U$Fzd|U%Qw5tHqdR9xO`V0D__xA=p}ZAv*9>12s{lV@IN6f_f7+&J2P{R z)+-t$$l@ql3gBBK?)6u3M)WKjKFX=hOXvS5C zhp8%2srsrEDM^h160uDS4Coz36EYXBYJ=OR)vku?)TgQ5`@&zRgZIquiCud;JjT<{ zL9OjprbnIOz*H5NZz64j>9y3RBk15m?TJ;U7B7j12a*j=f%<)F3K7JLTYw(gXfO99 zNO&uA#UK>C4BNg&IV$kiNSN*;9RO2Z`uCZC*u!T>4quaV&QK9Np*G{!5gy_GB#LAi#g_u7k=+e!<4?!kAdPi!%QEdT4I}*YVjxgVQ?&_B7NB4Eb?BhK3=uK{ z=c4Z2iKh01Ii29}KNHGVX=X?XO1kz7IVsOGuIo;aB~o#-N-ETIKtqXmM1Z;_Q&~68 zZF^$-*kp@~Dp{;wLE$udp?iKM-1jKe@>PZS?ZzThCo>L7-uF4<$cXS6huh-0mZ2Cc z8Kur-3A1KvS4|E%l9|p2>y(e|#vp3`TQSebf*Vj7Kh3x>N`wQ>%XKM-YX10$K_fLv zKI+>boA?@g1(^#kQ?0RI{7CH>1WFYYif@cDr%<%q2KP`wT7OJSph+E0_^VC^zWBmn zv?0EnV2`U*fASVmS_)0x;GoK-I9ZQ?09B)q1ZwuYrQY z%{D#wmZ0O3hp0L^hxBbYYd7W(P|wMRSBv4~;9>Z)%FaYvvfV96d~J_izu)F@$9h=7 zD`@!DFp?BEupk_{1k~|g+W2`Px*com&wMik% z7?@UkicyX_!T}V)QX9GuLG6~{ImZlF>{`zNb-vN^HA=_@m|Z3Wh)}%*gagVe>|VD| z=GK88mwGQy8fM+h9T1~y=;I(q(uizdDKt~36^CAsm=o}t&W?=P+ZZGM%R9j4o+r)r zYzpUR_s%8GAGfkt@<+>HZp?@{oMQOhN$J)@c!x2EbY_}W6^SQOP}s+XkEuCRD8dxm zlTtJ)tC-qmvB5nl-2?%ZZi4Ba1}B~=MSy~7tXWRPq53>6AvYFe9f$uomW-ISkdoYH zUyyY(hFAXwfv^pr@z#nG$Kl}iw$7jKnu>xFB@9$ee5K%m+bc3Aq}$MR0V{ZkT75-T zarI}Z@v)ms;9@-GQww@4<>V-hP2uC_HK*N2 zyToS3t*Y6`%7AJYd7-eH>HkOEgN80%0xzvbH7fWq6RRAFNRC2%)~=+!f{GV`YeyDp zjfLuXzETI?(guFo{`htDb(XLMVc=Q}eFpD&>DGQ8a=+%U%Ly-JmVJ4B)+ztN;(Rx* zz?Da>@jvOPn}vP7!@=v`-C1rBUROYPefiA;MoRZ-?JUP{&TWJI*_u)Br{MW{pgJpx65!qsvaifsJRI(7DH!rDHr|$ey^OxVaf)E`3euk034k^e*`8Y!1*bAM1t66bh=Q(R{#M7n=n(SH=!g@x1l*Tp zgjEyN%G@F(I~W?36sn74zVlpw36EPtj}l3~NZL0$q0qF*P~F`0Z|liK2boeo#qZ3> zTjTK5)`b&kgIXmged3j~QR8`kf8h7#m z>1u2|w187=px6O!Z$Z?PoeAvTtE_j!V*L#7`24&zyM6?)b1O67`ti|)h8_WI2n8S< z{0Lz?DQI6eXUiQ=918!j>uzOIy4s+1#nNJ+t-ChfV{S1yXJ>P5F!L~QcW{xIlF|jw z)-bzN`l5Wfw_=7y@n>l11p%u#b=hAXmkxXzuPT^T{_46yC}14q#4lby?_#ciwEIIW zg1-J4?X}7}VE=2SM^G26Q-YSi)-X~nw#LFd&zYO&r^}NGwX~;Q4Q!!Ac(p3U_%J64 z(a;92fUcm1zdPfkJ6hml2tn^D5T!jlSF@0#++l zL5E{QZ>-dfB>lg73OV_-b$pxBW__=vVowEletlT36nhV(|lIBifXKP(*5J(L$ai)5`S96jb z%4fPyNl*Eux)n1FIFuE>?H-a&Ng`_UV?L%|Lds+#jh z%t@vmwo9~u6y|*Q`7Q|FTv1%DfmS0ZhkBKTs3kn#h9R$0hdXa93xMScHYk*1Dv6bG z^44SkHD;lRv&;Wa^}iRtPnkQBS0~Mma!Pkgf$K4sOY6^Ulx;q>+ckNp89N(cD^8bq zOzDVPe}|0q=#c@n^}h#mPfd1a?{d8nth=%N$xPhrQguTWB;rfXB&xkMU2v6Qzjsz6 zyBpjamq|f<8GkdY4p3e@+nLL5o9|OXqRjYiGm~$(0U~&MJ02dYbP*fYe9xyaZ&2zZ z23=W1cZCtM-}_=Axgf#JgsQmgY25Z#qaYlrar|&v8y@yzBl%~H0ScW|-3H1wd%#S| ze;~tYi=;zCi6q*;8VbveCND|DzJ7|@x133=Z(Jzjjj12ufBuO+yKE#@QE)vxNzUrz zVZh|iojpf(D{^+M>{Y_io^X%}KWZnwvS0h#=mPOIp|uvDp23=bk5xZ@w632U%KbJ17FOEIockrUM5HKV-I}tqZT*?l$tMpFH_R=^_GncjmiBf%7+cH!QL0`b6&bIObR{g<%7nN zhg=Efu#LVm`_86Gg{wCvv=msf(>=t@VZ85r2!y>e^k1pjKBodl0R>?>u51}E)=eAX z-$RJD-pPeRp#v0ZxK2XeR7bwtSAz7DJoYaDs^>pkJ7{_@~*d%HqD``-IbB}&aTCg_{H;% z%MDtkxVEV2cYNIAbVXdFL!`$NrJZe;4mcykp5~{d(CbRnd}vFpDzQuT>{PkJHX|f- zeQm?gzTo;}V+@d7M8j1D(VD~7TDI>Cp%W3w8?&kqf_p2RpzmHGey8+}Fo;6FM^R|X zZR|;wUvZd!L?BrC7$qZyZ4+YK%TYLg-*Z`jMA zP@=Zi$!V{SBWcCsi_3h(hSwLzT=Ar`U_T$MFNu1P@KNw75#&E zWB*ywm?$3tb_;}z?IF9q%JgB~{ocr#dP+p86lz6klIV7KoHoMcdQ<$1ZjeHm^L=s! zp4sdyVyiNU5wVV0;ezjHt)BvI&?JX~T`Da077~Doohd;9!86$;=e?gh?h#xd@VMCe zJiIx%Gt1DZoaqHX2OQp4Rm%2#qiFf=eH?YLApt`9%jR3w2)1%ebsSE7uu|7qk!s}& z9I<8>HTxE?vxX`tTLa?d|wjniR z=N3yw1QWX+O$W2BY|gwvu>+fTLZQ0HJQ*?m&?6GbH?p9+q?NOLWP5~oDDD_ausrmE z`g|j$#y1~nIX2S<-Z7z+W#rQD@!SKE zUFTocdnnY~!~Kv{X6w_KPQu-F=r(@Dx%*&*hDxe#yF(q!u=D`zZLRNoo}KFtB;H zRV3W7uG<{i`r4wiV`l6oAxt39fL780K{#7SAsb?Esht}t?H|oRa-)7mw69|YN|`+>P6X6 z@t-}WdWU3jKVpYg2Pa!Cp>_^Ui>fn3vWBN5IK|3AIVa;*2a}&I7o5?V^3vmtHN0@c z3Ni+5&Q;vH(YNwoWA=Vc=<>T10`oIRu#Lu* z7JU1GVfZKtMH?PC;8!M*dSVs>zH9;mB%$3jV$^q;R7=x=;w0e+xnQcEM(9Z5?Y z7~d5W=r457-fulO`TZ}?i$iCy9eZqj1#?!fW!4*hJ8tBr8?Abn0t0g0f!y5`OYJ5+ zfUl5)teU5N3cr?+eVSKo3gRAd?cHi*dt*^iP!KUxfdf%;6qx263G2p~;!Q>8by|=Rtep|)5 zhiS&0d(g7R`lwKOGwIESozTrKq!{nx!Mfj2{lMz!q4Yj#G65m3p;9_YpSo{=C{?8R z_i~iS_LG5GqpcEPo;VE|RCKryd`NVXrESXxF{s1LmS7KIL#lCOMd%Z_wocw9V#sTL zi227hb*U_+<9DD)RlHCASXoghKT4>p%tz@8;F|AgKU<-Uob+zDn*?jGakBn(uLLe< z+!!Nt^0K37%YdxDJ-C66P2X&O$bf*o)(9&b^KgtEKEPk{XmmB@wtlswvD-|wy#Dy* z#0>?O^DAFXkg_}^0h+ioZCR#TxFXvnS>G-^ZOAXH$2{Ctoq6x~@A+|A$DPXWNX zH$7!b%z2EhIMqkV0>KDf$Jv-4H4`n3`|*|9;Kn8Ldh{dw`+Q_gp8LD&Or8{2)aI?+ z-+2xH8Bp)Ey^`ZI@jwD0voxURtz`C!g5&)sG%SnKvjPJXRAs_rMkewNEA$IQW+bmxzew16zo9$enu)mk<;R{EgjHmoc_DT%hoSg+^lgJOZA*)wZJ}A`v!XkU^K}&~nxUr?+k~Ws(wq{dO!!xi`rc+q z+JX)up4jZ`6#nuLDDQ*i-B;f!jHmECYN32PoIRRcs}@%U5bQrW#fV~(322NPAt(nD z2=pPPf4IqgaWK#q*Qvo(FU_BNAqTw*V0%~!JNqN06)ID zKtILk8Tw!W%r@uD@y+u!hjX~N3>CpVM;pxr+b~ovjP(;g`Eu`rb16If(8Ci;o#ej1F=qhv9x#Up zzgU#w;@-czn+5<*)a_Y@XuoM`tH&8$GKk%9Z}0K}e?5e2vQLLOJzqFu%5>pd8sp;YsaiCrvwrnJvZ%aueak$w{#+_WOY4PT)w{1?U)v;Nd5!vO681b4LwVXb{$R#)TUU34s=unA; zX;Dn^pAzv?n~hlw1w$akxaFBuU%uhKc@i$QTb=P*Xdpo|PS?%Nz=YI@1t z$7$=WaGg-DRYJms*T$^*-oS5i$ntYAzwoHAkUvQ(Y_q9|qimXYO^`WZvBXD6=Aqn6 z*SYFHM1MS(m?02uT@OD+^;y}>?~~bsw-FCRWir>fSDu&6C%OXcL22;-2^SA%vfy7* zrsiIU{qq78I2KJJ>xbc5;a{@UK~qTubo?~BN{ZAe=9$;kxwq2{`Wm!npp-=hWHr0wcN)w<2%x26OVwRf(vW#rQNNv+H8Qs}>>F?T^zrQsl@q#3(( z029nL2!B}UD9Ar>>_F}&0sE|P&7p5q@DvEhzs#oMz1}#cq`aUoY)JMqzjM&sB;j8f zi9)qZWHPuE?h2lo@te3ChBtn5vOrk*S}BhO6X8{_zklC5S+(G6)CfDL{1VenawUc1 z%wGTq{rPF{X)rXTK@DT4#?$VNUH@QD|i@>X23@miA%u(KWg-AktozP8jDh17zBqi{AsFC99t>va%H_GZeU;dcUAQl*U^v9An$6l;m zS74ct_N#uO&&2x7Pmw3ps;{RB^OAC2y)x1(U+2WuxFP0c5-3LgRF&jn&Eorn#nPPc z&}|QI<2{-Gd~H`FDdy`#$ zwrIn>ok?L?hQ>c`ard)-Hb=6pDEg)p!7yEs@*g{{%)A+P99|?=;kY^IYAWB7o`ps+ zjE^iYzO4jfE{WUny?2wj7n1#`ctcL2*cM>4xVoot%(2WJTNFDAc&jyM{>op+QK{i> z*b&{>cSIw~YBNoQq}qbCM{yCv^&opunoLZn{Zp@1E;y?SLs@C*ligu@!pV_W{&K$# z+y-W+OEx}zy+G1NgCs9r>I~NJggQMd-|0HlnqL2#L)_$4RJXwShuR)jr-Y{=$D!M0 zkj}6qa^@@^`=pE1(mr_W;-4;|WdAwJ<$#;7w(%`4({K4IE^&Dlictd!uVy9xGQ>{M z{2I?wk6CpEUQ^W$;fZ3)gNfmXlSwNfetZt621(4`cgKq+;#k$yW-({5G;K}WDwxK$ zJYDx|_~cOgmNY|xzQ+02_^sE$@qCyu!uH|CPts4O63cY1<=`-8kMeAunC#eas=0O4 zM*H#A!K*v?e>{8#71U{bsj-}y7?x-m2;0361@DsWdf0sy zHKZIF+1}GgeXJ1^dBO*U61o;lqw>_QK-$D6saKn7+G}2Cn{v>aw;M4{4xqi##ve`Oq3vjjEHd70@T_A8V^vd0d zM=Yz4v!L$8%{c(b(K?_gbE~q2R)zOwf41@`S;;)F$C^nvR<#XyC|y%2jv)=U)@5c4 z`rA@cc*e0QN3NNc-a7<|*#rgTvrn`c8$un;6B{F&lpqKXx*^ziyxbpTul3)CO$G36N5iI|RrG%hn<}vU zufwJy?5KL-!6)Z!%_5`(nZQu*f;1~r{!CsHxK#eJ?MO~;seJW)O*z1+Gw2{t6xkz{ zaNi`5LN!o|sWMuqt*T%@Me+oXn|JX!Eb6v6vH}bchZRYJa`=B8IOW|o8zB#zM*lAZ zr@&eLuLGwbV0t&_dTTS<1&P{pQ9~Z4ol(|Rca=UEl~aKzbtGSX9eNH5$8-nXf5zTD zz10<}g)V9%7}kubs+k_4c#cNH^a$9O)~w)A@+kXvPiN5sO6pZf{M{6uR^QnGm#*Odl2Hc_^Eu{Y)L?j*Jj>+6 zEw`xzhs!yJDyqlKhEj2Z@*;VB8PcivdyCgI0au{qE1e#z3)z>OPTuNt=bzwLzQmZ`h% zk=Os%obX4F)M`x{uU zwCzHKUFhJI@M=GWjh=ELrf0~84x@$G4rL$poqY1gefhR_<9%dyd%LavWpGbfMy2+_@)!_Xigj%Bs)UCwVW*ddUH0SLxD2RtY@vuX~@u9Kt^@ zb~03T7X-g<`9rT%F5|;3ueR+`@8+u)A*^}9o_4IS=#!yWtQfi4YTKTqft4a?AZcKu zcKurCr0L+$s_ua2e%FD_MUro4dc|8c;1*SDBH|n_XYPNJG~VTE@ERGKMKA8$=_nik zHOTN_nVs*-|jqM4ALdz1=qkhoX*vSGZg_E@! zR0HYTa$IK<%Xht9b&^hTbn-$;BTqdyP2}1)wML$nJ9;0suVlO81^)))l8X;sC_PNw{6Yr<#(M3nUcJjp#{uMV~|4h>x4lQH3G0j(XGA8 z8#K!Hvid+l^G?mic@9<%?^fuo+b1tKl}L5)Lz_(!#)sv@k>QJN66K9rhv-wdFJPjT zMV~Lj#c#;Nwq8f=$$|crq*d4NTppvFnFn^;Zj;%Ijin>=m9C{yNxF+i-#YW(zXkoD zzXmWG)mgjyip9HJlsNqCgV)2iR%RoEAOHQeS(W5Bvd>NfXm4FtEwWksQmnOQMvt&e z%<0cS$}Ta0|9_)=%f&5M*K1CVzZiWa8{PvHBA%ueawLV9IQ;s??V8PDFS)Z!!@VnOq79S? zfNG9~|FDTPAHNGSt|G2%!A1AQr;DS7v&Q%hwC7(Vli^3ZGR}X04a^txt>^5N*d~r_ z*$tO3doCIu7Lv^(S76-X6bu}Pi_%!AYO#Y0I@NbDXS7tf$92l5+HUKTZfO(T}ZeXhs8T&g|_95vZCGVAL#}ghR zlX(yEYh`S5dKX~1diAxumU4${8zzI)!U-Z;9K)=Nxe}I9<>5sS{P6qgspE%#q^tnT$Cy-1-RT4v zGR+rih_AZ)H*_G+r#YgY`{!CF)$D6FckG{(yN>{W25aXGOIEJwJhkQ8e1*+qX8>0- zE*(5YU6PW&BHUIL%eKgJb`<=N0_E$b5;mQ7OLm93vYR`f27Wj%?F_jLr_1J%Re!^# z^RCfoCifLd&yh?hFIjidrA@7)eAfdSC{1!XO&7e3gFu}omZxnw;3L0>S9Zj}r14(y zfbpoOO!=<;dRgKAT1Ca{yNl~1Tjef!heJRX{|9Mp3;~|F0eKA=Lw!&0M)Yz*4@;%E z@_x-%Zg}Kz54{q=^V;kCTb8@n{1RzDR=?*kn*geeykSm!)uOq^LL;*D8?v>i(K>A^JIZ- zS8IMH_;`{!^U3PKrV#M(l?__J%py?VBcL2}m0{b7`o;BM`u_p9pj#XVb{w5US%GsS zjSOw8z#YdeppGN3TKKb+FS~#BTFsAp0(n@zHOjheZu~_nRM^lskxk)=EB-qRrH!h4W>COvfRxY?9Dq^)oBWT}I z1%8;&v74=`5r+nCpSZvp`zRSM{?J z&l*wpyoWkrpAvWs;3ki?|CciIM~YsJ{||y z<8T%7Z33pbjz?>Gf#n1Es1abV0&?0Bws@_Fou7m^VpqpsIdm(*M+$hR%Z*|csf71E zRZKDu5}qFio@&Fz#gfF@ln6gm<#AJdfNtC+xWWbUCzP?zFC`}?1YtgQ2QxLB%OsODrbuip{a06y?1)^VZ7B2S>J z7z6ig1=faW2gsb{2aXK@50GI&KR{+GFd2g;{V>mu0nKQ7mwoL99#Ycd*$g}ltGdsH z8F+A*KX6Rw&7U3MPMSmg8V3U&_)$4O?m*&|OEGYsI#!8;zR3z)Ey&>M>gTe~DWM4fDt~Pt From 2d3a0c5b108b94ef39dc105493d2e66b0dc57238 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 24 Oct 2022 13:33:50 +0300 Subject: [PATCH 035/179] Updated app.png icon --- apps/rinkulainen/app.png | Bin 4656 -> 3177 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/rinkulainen/app.png b/apps/rinkulainen/app.png index 632cf17e033e1997ec76c7061c91ee76d125ea1c..50782c48d1fdd50e63b9f15db8f472ee06c21a06 100644 GIT binary patch delta 2084 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 IM6N<$f_wDKDF6Tf From a83ea008de2700ad23adee97f6490606c16d61e6 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 24 Oct 2022 13:34:28 +0300 Subject: [PATCH 036/179] Update app-icon.js --- apps/rinkulainen/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/rinkulainen/app-icon.js b/apps/rinkulainen/app-icon.js index b27f89b2d..0618f7891 100644 --- a/apps/rinkulainen/app-icon.js +++ b/apps/rinkulainen/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwwkBIPsPAAwVN+AAKFaIxPFpYvJFpovJFpovHFp4vHFp4vGFyIvFFyIvEFyQvEFyQvDFyYvDFyYvCFygvCFygvBFyovBFyvwFy0Pc6YvTC4ajDFpv//4XFF8otBF44HBFywvKFof/R4gXBF8QuEF/4vZFwovwC4wvgFwwvGBBAhDF5oXGF/4v/FAovRFAbtCF6hoKF5QAG")) +require("heatshrink").decompress(atob("mEwwkEogA0/4AKCpNPCxYAB+gtTGJQuOGBAWPGAwuQGAwXG+chiMRiU/C6HyiDpDgMvC5ItFCoYADGIoXIFoIqDGgUBC5nxB4IoE+YYBj4XLBwJxGJ4IwEC4wuBiYEBmUhiUjAoMxGAgXGmAuCDYIACCYIwBgYXJBYSQGD4IjBC5HyE4QOBgU/+cgEAQ3BTAQXFBQImBN4p/BHARgCC4swCYIaBT4gGDiBgCC4syQ4JVENIsggTvKBgYHG+BRCC5KdDWIYXOiEPC4oUCC8hHUmTJBO44XMCgSnH+SnLa5IABfILXJCgINBgA9CAAnzEIYXF+QKCJAMCn/zkQXCEgJtBR479CEwIADCQRpEC4wLBJAInBAAQ3BD4KxDC4wTBiatCkMSkYFBmKAEa48QGAR1GP4gXHGAMBDAnzEAKvEC44wCgJzC+QGCBwgXIRwoACJ4oXDp4JEFQQACGgYAC+gXJGIMhiMRiR9GC5YALC4hgFABgWEGCIuFGCIWGGB4uHGJwVJAFY")) From 13d205d6f38de0b18125669c0501e1636e1b76df Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 31 Oct 2022 16:37:47 +0200 Subject: [PATCH 037/179] Added weekdays and hour line moving by minutes Also made the watch face a tiny bit wider --- apps/poikkipuinen/app.js | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/apps/poikkipuinen/app.js b/apps/poikkipuinen/app.js index 870b365e1..1e91cbb63 100644 --- a/apps/poikkipuinen/app.js +++ b/apps/poikkipuinen/app.js @@ -5,6 +5,7 @@ // www.jukiokallio.com require("Font5x9Numeric7Seg").add(Graphics); +require("FontSinclair").add(Graphics); // settings const watch = { @@ -12,6 +13,7 @@ const watch = { bgcolor:g.theme.bg, fgcolor:g.theme.fg, font: "5x9Numeric7Seg", fontsize: 1, + font2: "Sinclair", font2size: 1, finland:true, // change if you want Finnish style date, or US style }; @@ -20,9 +22,9 @@ const watch = { watch.w = g.getWidth(); // size of the background watch.h = g.getHeight(); watch.x = watch.w * 0.5; // position of the circles -watch.y = watch.h * 0.46; +watch.y = watch.h * 0.43; -const dateWeekday = { 0: "Sunday", 1: "Monday", 2: "Tuesday", 3: "Wednesday", 4:"Thursday", 5:"Friday", 6:"Saturday" }; // weekdays +const dateWeekday = { 0: "SUN", 1: "MON", 2: "TUE", 3: "WED", 4:"THU", 5:"FRI", 6:"SAT" }; // weekdays var wait = 60000; // wait time, normally a minute @@ -49,8 +51,9 @@ function draw() { var dateDay = date.getDate(); var dateMonth = date.getMonth() + 1; var dateYear = date.getFullYear(); - var dateStr = dateWeekday[date.getDay()] + " " + dateMonth + "." + dateDay + "." + dateYear; - if (watch.finland) dateStr = dateWeekday[date.getDay()] + " " + dateDay + "." + dateMonth + "." + dateYear; // the true way of showing date + var dateStr = dateMonth + "." + dateDay + "." + dateYear; + if (watch.finland) dateStr = dateDay + "." + dateMonth + "." + dateYear; // the true way of showing date + var dateStr2 = dateWeekday[date.getDay()]; // Reset the state of the graphics library g.reset(); @@ -65,7 +68,7 @@ function draw() { // watch face size var facew, faceh; // halves of the size for easier calculation - facew = 40; + facew = 50; faceh = 59; // save hour and minute y positions @@ -88,9 +91,11 @@ function draw() { g.drawLine(watch.x - facew, y + watch.y, watch.x - facew + w, y + watch.y); // get hour y position - var hour = date.getHours() % 12; - if (hour == 0) hour = 12; - if (i == hour) houry = y; + var hour = date.getHours() % 12; // modulate away the 24h + if (hour == 0) hour = 12; // fix a problem with 0-23 hours + var hourMin = date.getMinutes() / 60; // move hour line by minutes + if (hour == 12) hourMin = 0; // don't do minute moving if 12 (line ends there) + if (i == hour) houry = y - (lineh * hourMin); } // draw minute meter @@ -120,9 +125,11 @@ function draw() { g.drawLine(watch.x - facew + timexpad, watch.y + houry, watch.x + facew - timexpad, watch.y + minutey); // draw date - var datey = 12; + var datey = 15; g.setFontAlign(0,-1); g.drawString(dateStr, watch.x, watch.y + faceh + datey); + g.setFontAlign(0,-1).setFont(watch.font2, watch.font2size); + g.drawString(dateStr2, watch.x, watch.y + faceh + datey*2); // queue draw queueDraw(); From b91a08a4200edfb6eaa993a1287301c5ccbb5574 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 31 Oct 2022 16:38:22 +0200 Subject: [PATCH 038/179] Updated screenshot --- apps/poikkipuinen/screenshot1.png | Bin 52829 -> 6045 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/poikkipuinen/screenshot1.png b/apps/poikkipuinen/screenshot1.png index e9422ee437cb4f056ab93def1eed716ad4a3b7e0..23fcc348c14a5062d2525910be357618bd203256 100644 GIT binary patch delta 5637 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 literal 52829 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 Date: Mon, 31 Oct 2022 16:41:51 +0200 Subject: [PATCH 039/179] Fixed positioning --- apps/poikkipuinen/app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/poikkipuinen/app.js b/apps/poikkipuinen/app.js index 1e91cbb63..98178cc9d 100644 --- a/apps/poikkipuinen/app.js +++ b/apps/poikkipuinen/app.js @@ -1,4 +1,4 @@ -// Poikkipuinen +// Laatikkoinen // // Bangle.js 2 watch face // by Jukio Kallio @@ -22,7 +22,7 @@ const watch = { watch.w = g.getWidth(); // size of the background watch.h = g.getHeight(); watch.x = watch.w * 0.5; // position of the circles -watch.y = watch.h * 0.43; +watch.y = watch.h * 0.41; const dateWeekday = { 0: "SUN", 1: "MON", 2: "TUE", 3: "WED", 4:"THU", 5:"FRI", 6:"SAT" }; // weekdays @@ -125,7 +125,7 @@ function draw() { g.drawLine(watch.x - facew + timexpad, watch.y + houry, watch.x + facew - timexpad, watch.y + minutey); // draw date - var datey = 15; + var datey = 14; g.setFontAlign(0,-1); g.drawString(dateStr, watch.x, watch.y + faceh + datey); g.setFontAlign(0,-1).setFont(watch.font2, watch.font2size); From 6518dbedfa85a71f64ff919e39a02ff80ad52b8c Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 31 Oct 2022 16:53:11 +0200 Subject: [PATCH 040/179] Wrong app name in the comments --- apps/poikkipuinen/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/poikkipuinen/app.js b/apps/poikkipuinen/app.js index 98178cc9d..026f5ea5b 100644 --- a/apps/poikkipuinen/app.js +++ b/apps/poikkipuinen/app.js @@ -1,4 +1,4 @@ -// Laatikkoinen +// Poikkipuinen // // Bangle.js 2 watch face // by Jukio Kallio From f56806cbd1af47d9309bfb60e3e033404822e6ed Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 31 Oct 2022 17:08:00 +0200 Subject: [PATCH 041/179] Updated hour line Made hour line move by 15-minutes to make it easier to read + other tiny visual modifications --- apps/poikkipuinen/app.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/poikkipuinen/app.js b/apps/poikkipuinen/app.js index 026f5ea5b..0bf09c5e5 100644 --- a/apps/poikkipuinen/app.js +++ b/apps/poikkipuinen/app.js @@ -79,7 +79,7 @@ function draw() { var lines = 13; var lineh = faceh * 2 / (lines - 2); for (var i = 1; i < lines; i++) { - var w = 2; + var w = 3; var y = faceh - lineh * (i - 1); if (i % 3 == 0) { @@ -93,7 +93,8 @@ function draw() { // get hour y position var hour = date.getHours() % 12; // modulate away the 24h if (hour == 0) hour = 12; // fix a problem with 0-23 hours - var hourMin = date.getMinutes() / 60; // move hour line by minutes + //var hourMin = date.getMinutes() / 60; // move hour line by minutes + var hourMin = Math.floor(date.getMinutes() / 15) / 4; // move hour line by 15-minutes if (hour == 12) hourMin = 0; // don't do minute moving if 12 (line ends there) if (i == hour) houry = y - (lineh * hourMin); } @@ -104,7 +105,7 @@ function draw() { lines = 60; lineh = faceh * 2 / (lines - 1); for (i = 0; i < lines; i++) { - var mw = 2; + var mw = 3; var my = faceh - lineh * i; if (i % 15 == 0 && i != 0) { From cf5b6ab14fae2d891e98e971968b6e0b99b74b14 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 31 Oct 2022 17:40:08 +0200 Subject: [PATCH 042/179] Create ChangeLog --- apps/rinkulainen/ChangeLog | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/rinkulainen/ChangeLog diff --git a/apps/rinkulainen/ChangeLog b/apps/rinkulainen/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/rinkulainen/ChangeLog @@ -0,0 +1 @@ +0.01: New App! From 4d8a6e43f122db3ee0f021d65dcc55467565bd31 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 31 Oct 2022 17:40:45 +0200 Subject: [PATCH 043/179] Create ChangeLog --- apps/poikkipuinen/ChangeLog | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/poikkipuinen/ChangeLog diff --git a/apps/poikkipuinen/ChangeLog b/apps/poikkipuinen/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/poikkipuinen/ChangeLog @@ -0,0 +1 @@ +0.01: New App! From beb8f52eb981783792d2eb2a4d7efa1dde3907a7 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Mon, 31 Oct 2022 17:41:07 +0200 Subject: [PATCH 044/179] Create ChangeLog --- apps/henkinen/ChangeLog | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/henkinen/ChangeLog diff --git a/apps/henkinen/ChangeLog b/apps/henkinen/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/henkinen/ChangeLog @@ -0,0 +1 @@ +0.01: New App! From b5611ead785f29522a3152ede168efa8cb9e182c Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Tue, 1 Nov 2022 12:31:56 +0200 Subject: [PATCH 045/179] Create app.js --- apps/palikkainen/app.js | 184 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 apps/palikkainen/app.js diff --git a/apps/palikkainen/app.js b/apps/palikkainen/app.js new file mode 100644 index 000000000..42013af69 --- /dev/null +++ b/apps/palikkainen/app.js @@ -0,0 +1,184 @@ +// Palikkainen +// +// Bangle.js 2 watch face +// by Jukio Kallio +// www.jukiokallio.com + +require("Font6x8").add(Graphics); + +// settings +const watch = { + x:0, y:0, w:0, h:0, + bgcolor:g.theme.bg, + fgcolor:g.theme.fg, + font: "6x8", fontsize: 1, + finland:true, // change if you want Finnish style date, or US style +}; + +// set some additional settings +watch.w = g.getWidth(); // size of the background +watch.h = g.getHeight(); +watch.x = watch.w * 0.5; // position of the circles +watch.y = watch.h * 0.45; + +const dateWeekday = { 0: "SUN", 1: "MON", 2: "TUE", 3: "WED", 4:"THU", 5:"FRI", 6:"SAT" }; // weekdays + +var wait = 60000; // wait time, normally a minute + + +// timeout used to update every minute +var drawTimeout; + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, wait - (Date.now() % wait)); +} + + +// main function +function draw() { + // make date object + var date = new Date(); + + // work out the date string + var dateDay = date.getDate(); + var dateMonth = date.getMonth() + 1; + var dateYear = date.getFullYear(); + var dateStr = dateWeekday[date.getDay()] + " " + dateMonth + "." + dateDay + "." + dateYear; + if (watch.finland) dateStr = dateWeekday[date.getDay()] + " " + dateDay + "." + dateMonth + "." + dateYear; // the true way of showing date + + // Reset the state of the graphics library + g.reset(); + + // Clear the area where we want to draw the time + g.setColor(watch.bgcolor); + g.fillRect(0, 0, watch.w, watch.h); + + // setup watch face + const block = { + w: watch.w / 2 - 6, + h: 18, + pad: 4, + }; + + // get hours and minutes + var hour = date.getHours(); + var minute = date.getMinutes(); + + // calculate size of the block face + var facew = block.w * 2 + block.pad; + var faceh = (block.h + block.pad) * 6; + + + // loop through first 12 hours and draw blocks accordingly + g.setColor(watch.fgcolor); // set foreground color + + for (var i = 0; i < 12; i++) { + // where to draw + var x = watch.x - facew / 2; // starting position + var y = watch.y + faceh / 2 - block.h - block.pad / 2; // draw blocks from bottom up + if (i > 5) { + // second column + x += block.w + block.pad; + y -= (block.h + block.pad) * (i - 6); + } else { + // first column + x += 0; + y -= (block.h + block.pad) * i; + } + + if (i < hour) { + // draw full hour block + g.fillRect(x, y, x + block.w, y + block.h); + } else if (i == hour) { + // draw minutes + g.fillRect(x, y, x + block.w * (minute / 60), y + block.h); + + // minute reading help + for (var m = 1; m < 12; m++) { + // set color + if (m * 5 < minute) g.setColor(watch.bgcolor); else g.setColor(watch.fgcolor); + + var mlineh = 1; // minute line height + if (m == 3 || m == 6 || m == 9) mlineh = 3; // minute line height at 15, 30 and 45 minutes + + g.drawLine(x + (block.w / 12 * m), y + block.h / 2 - mlineh, x + (block.w / 12 * m), y + block.h / 2 + mlineh); + } + } + } + + + // loop through second 12 hours and draw blocks accordingly + if (hour >= 12) { + g.setColor(watch.bgcolor); // set foreground color + + for (var i2 = 0; i2 < 12; i2++) { + // where to draw + var x2 = watch.x - facew / 2; // starting position + var y2 = watch.y + faceh / 2 - block.h - block.pad / 2; // draw blocks from bottom up + if (i2 > 5) { + // second column + x2 += block.w + block.pad; + y2 -= (block.h + block.pad) * (i2 - 6); + } else { + // first column + x2 += 0; + y2 -= (block.h + block.pad) * i2; + } + + if (i2 < hour % 12) { + // draw full hour block + g.fillRect(x2, y2, x2 + block.w, y2 + block.h); + } else if (i2 == hour % 12) { + // draw minutes + g.fillRect(x2, y2, x2 + block.w * (minute / 60), y2 + block.h); + + // minute reading help + for (var m2 = 1; m2 < 12; m2++) { + // set color + if (m2 * 5 < minute) g.setColor(watch.fgcolor); else g.setColor(watch.bgcolor); + + var mlineh2 = 1; // minute line height + if (m2 == 3 || m2 == 6 || m2 == 9) mlineh2 = 3; // minute line height at 15, 30 and 45 minutes + + g.drawLine(x2 + (block.w / 12 * m2), y2 + block.h / 2 - mlineh2, x2 + (block.w / 12 * m2), y2 + block.h / 2 + mlineh2); + } + } + } + } + + + // draw date + var datey = 11; + g.setFontAlign(0,-1).setFont(watch.font, watch.fontsize).setColor(watch.fgcolor); + g.drawString(dateStr, watch.x, watch.y + faceh / 2 + datey); + + + // queue draw + queueDraw(); +} + + +// Clear the screen once, at startup +g.clear(); +// draw immediately at first +draw(); + + +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); + + +// Show launcher when middle button pressed +Bangle.setUI("clock"); From fdb96afb3d5efd0320a50a70d5e1a6864b65e5e5 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Tue, 1 Nov 2022 12:35:54 +0200 Subject: [PATCH 046/179] Add app.png --- apps/palikkainen/app.png | Bin 0 -> 2242 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/palikkainen/app.png diff --git a/apps/palikkainen/app.png b/apps/palikkainen/app.png new file mode 100644 index 0000000000000000000000000000000000000000..142d429e97d532e3893677ffb658051b261fedd4 GIT binary patch literal 2242 zcmai0c~BE)6kkwI#jze0>y<8}qtaxPAPQ?1ib;^D(a2Fy1RIh~vbbcI-31ax8Ldi1 zyue~dP-|5@k--tHS0h!6ZKstM4?Ixts3_Jeh)0pyZxiGYZU5LL@B6*?d+&SKCPy=K zs*m?a-Vg-&s3H`R;9JZ;p6=i?*7fC=5abq1M8|P)>KUkxN)c)GR1z+-q|g9|AX%t| z*6J4EoFEA|5@rm3bnFByAoLg<8>kkmX*q5pA~G2~DsyJEE^~n{SPzGWc*`s(AV|SE zt-z8(npxC>!46&&{N|4lSm03M7GQ9kS|gBC3@!*11&YLQh_^t-=nZJ3BD~!gNEmG5 zI2uKejEoFXMu3Q7jEE#SI2aL25vf!NG=!|x%xNt`Gwa7wI5`wJt78b7BPg?g=hP-q zX&eT_02j2A>vbL6bQ(iCnDsgYC-D^A%&~|>Btg3B;})Vb8Z+CTE|55cM}WGxn>t4r z-lNVVJ=AFv#Zjz@qC0}>=Ar}cVF=RwZWD`^ewVUZ{om>-Dc!EYa>{g&xb`A+i|LI6 zHrh(#NF>fuX^ak6ri1MHITFX`1=SE1oQzWtAgL^<1_nH`Y-J z)DfSW(u42<9F(1qN-ozhlz|`t#zsz^B2X#i6D7eDCkmw^rwdRv6xb35t3t~GEvXoE zvqT~kOQI!GG$0U_O!5~?QL)&;?9c|&qt|lU|I_DZKp@lWP>$e8+#xwm4@+cW|OCW#BTj3?60#eTBhc1_J@A zXccJqff0Zq6^jD9TV$AU!1n%xB3-ZYCNvq+BY5Y{yKE9*=R5-&3amP$W7h$pV_V{8 zup$|-3-=c7Zh|0}#RTYu9z6g-WAoDT>iw6__B|6i4Bk0TG;i$o)CywvkE^9#qxWx= z){&30_I!W!YO7ggE{Ip=3_Bru(dTeXX#pI`jH^BEbHC+yQK7#2o~)6zHCnfvwf4Jo zYN#?WdC^uwbEXMyC|vu=;ihkhli_{|T=-!5Fdz3_dy+?G4De6CRgoOCwzanKrkC6$ ze(B>C+wNI!sBYXVIBs}yh%U-sQ?-27a_s0l&5MgQIy~z@P|O`9w}m$K{Y!YV^gObr zEot=reJAZqUGmPYuj_= zl;27^Vhn8@UN5((ZB5?k&$q_j+&sO0!fj)9W$KO^@J{ohBj&IWB=X}Q7fW$yIw;U` zl_D(KwB$iySmaXipzPPRM<08S{C2wV=wsK!-3d)|p89U799L{^amS_{OU)XxWMjT! z%(DF6MO3zWiM?&nXe!%dT~6-d;R>c-gI6WC*tK#%7ko7QXzY3}vugKTV zd(}U0Lvz6`RpO97PvW0GqI2?kogU+{V)eQ4U)g`j96H$dipRXO&-dGJ`>%5V>UAMv z!>A*xyqDeWmC%?WdFg!{I`FegQZv$8nN_~e=L~(&?UGynC&e|PWp3hr(>!-US0UKu z>q1tCH$oxnuIru+sN5cMWK+$Gd!H$6Eh8?5XsWj*Rvl{k;h@?!aIfV4%H;DybL9^j z>ghf1*NQyt!_dA*TW!gjO{DI4vSu^cXuTi^ke(8tq Cmo*Lm literal 0 HcmV?d00001 From 5e26fb360b3aebed6841d6f8a02ad02124ef1b69 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Tue, 1 Nov 2022 12:36:44 +0200 Subject: [PATCH 047/179] Create app-icon.js --- apps/palikkainen/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/palikkainen/app-icon.js diff --git a/apps/palikkainen/app-icon.js b/apps/palikkainen/app-icon.js new file mode 100644 index 000000000..a99602121 --- /dev/null +++ b/apps/palikkainen/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkBiIA0/4AKCpMfCxYAB+ItTGJQuOGBAWPGAwuQGAwXvCyJgFC+PwgAAEh4X/C/6//A4gX/C/6//A4QX/C/6/vC6sfCyPxC+ZgSCwgwRFwowRCwwwPFw4xOCpIArA")) From 55369b314e9e3735e254a0f3df99ef889710270e Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Tue, 1 Nov 2022 12:38:20 +0200 Subject: [PATCH 048/179] Create metadata.json --- apps/palikkainen/metadata.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 apps/palikkainen/metadata.json diff --git a/apps/palikkainen/metadata.json b/apps/palikkainen/metadata.json new file mode 100644 index 000000000..d63e5ffc2 --- /dev/null +++ b/apps/palikkainen/metadata.json @@ -0,0 +1,15 @@ +{ "id": "palikkainen", + "name": "Palikkainen - A blocky watch face", + "shortName":"Palikkainen", + "version":"0.01", + "description": "A minimal watch face consisting of blocks.", + "icon": "app.png", + "screenshots": [{"url":"screenshot1.png"}], + "tags": "outdoors", + "supports" : ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"palikkainen.app.js","url":"app.js"}, + {"name":"palikkainen.img","url":"app-icon.js","evaluate":true} + ] +} From b428cad98c194474f3cd4da2de37f5fddd7c49eb Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Tue, 1 Nov 2022 12:39:27 +0200 Subject: [PATCH 049/179] Add screenshot --- apps/palikkainen/screenshot1.png | Bin 0 -> 31010 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/palikkainen/screenshot1.png diff --git a/apps/palikkainen/screenshot1.png b/apps/palikkainen/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..7abbf67302cfe25ed2b2d7c7f97265fdc5fb33ad GIT binary patch literal 31010 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 literal 0 HcmV?d00001 From 1526cef140218651d5fe32ff9da955601b9cc60c Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Tue, 1 Nov 2022 12:40:50 +0200 Subject: [PATCH 050/179] Create README.md --- apps/palikkainen/README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 apps/palikkainen/README.md diff --git a/apps/palikkainen/README.md b/apps/palikkainen/README.md new file mode 100644 index 000000000..81d857209 --- /dev/null +++ b/apps/palikkainen/README.md @@ -0,0 +1,7 @@ +# Palikkainen + +By Jukio Kallio + +A minimal watch face consisting of blocks. Minutes fills the blocks, and after 12 hours it starts to empty them. + +![](screenshot1.png) From 50de14f1dc6d5f0052eccbf57c91789137ba2f39 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Tue, 1 Nov 2022 12:44:14 +0200 Subject: [PATCH 051/179] Update metadata.json --- apps/palikkainen/metadata.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/palikkainen/metadata.json b/apps/palikkainen/metadata.json index d63e5ffc2..4ed8be817 100644 --- a/apps/palikkainen/metadata.json +++ b/apps/palikkainen/metadata.json @@ -5,7 +5,8 @@ "description": "A minimal watch face consisting of blocks.", "icon": "app.png", "screenshots": [{"url":"screenshot1.png"}], - "tags": "outdoors", + "type": "clock", + "tags": "clock", "supports" : ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ From 6b5e904e82023fb1163d980de9b0506df11226bb Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Wed, 2 Nov 2022 12:59:37 +0200 Subject: [PATCH 052/179] Create app.js --- apps/pisteinen/app.js | 121 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 apps/pisteinen/app.js diff --git a/apps/pisteinen/app.js b/apps/pisteinen/app.js new file mode 100644 index 000000000..a455875ec --- /dev/null +++ b/apps/pisteinen/app.js @@ -0,0 +1,121 @@ +// Pisteinen +// +// Bangle.js 2 watch face +// by Jukio Kallio +// www.jukiokallio.com + + +// settings +const watch = { + x:0, y:0, w:0, h:0, + bgcolor:g.theme.bg, + fgcolor:g.theme.fg, +}; + +// set some additional settings +watch.w = g.getWidth(); // size of the background +watch.h = g.getHeight(); +watch.x = watch.w * 0.5; // position of the circles +watch.y = watch.h * 0.5; + +var wait = 60000; // wait time, normally a minute + + +// timeout used to update every minute +var drawTimeout; + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, wait - (Date.now() % wait)); +} + + +// main function +function draw() { + // make date object + var date = new Date(); + + // Reset the state of the graphics library + g.reset(); + + // Clear the area where we want to draw the time + g.setColor(watch.bgcolor); + g.fillRect(0, 0, watch.w, watch.h); + + // setup watch face + const hball = { + size: 9, + pad: 9, + }; + const mball = { + size: 3, + pad: 4, + pad2: 2, + }; + + // get hours and minutes + var hour = date.getHours(); + var minute = date.getMinutes(); + + // calculate size of the hour face + var hfacew = (hball.size * 2 + hball.pad) * 6 - hball.pad; + var hfaceh = (hball.size * 2 + hball.pad) * 4 - hball.pad; + var mfacew = (mball.size * 2 + mball.pad) * 15 - mball.pad + mball.pad2 * 2; + var mfaceh = (mball.size * 2 + mball.pad) * 4 - mball.pad; + var faceh = hfaceh + mfaceh + hball.pad + mball.pad; + + g.setColor(watch.fgcolor); // set foreground color + + // draw hour balls + for (var i = 0; i < 24; i++) { + var x = ((hball.size * 2 + hball.pad) * (i % 6)) + (watch.x - hfacew / 2) + hball.size; + var y = watch.y - faceh / 2 + hball.size; + if (i >= 6) y += hball.size * 2 + hball.pad; + if (i >= 12) y += hball.size * 2 + hball.pad; + if (i >= 18) y += hball.size * 2 + hball.pad; + + if (i < hour) g.fillCircle(x, y, hball.size); else g.drawCircle(x, y, hball.size); + } + + // draw minute balls + for (var j = 0; j < 60; j++) { + var x2 = ((mball.size * 2 + mball.pad) * (j % 15)) + (watch.x - mfacew / 2) + mball.size; + if (j % 15 >= 5) x2 += mball.pad2; + if (j % 15 >= 10) x2 += mball.pad2; + var y2 = watch.y - faceh / 2 + hfaceh + mball.size + hball.pad + mball.pad; + if (j >= 15) y2 += mball.size * 2 + mball.pad; + if (j >= 30) y2 += mball.size * 2 + mball.pad; + if (j >= 45) y2 += mball.size * 2 + mball.pad; + + if (j < minute) g.fillCircle(x2, y2, mball.size); else g.drawCircle(x2, y2, mball.size); + } + + + // queue draw + queueDraw(); +} + + +// Clear the screen once, at startup +g.clear(); +// draw immediately at first +draw(); + + +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); + + +// Show launcher when middle button pressed +Bangle.setUI("clock"); From eec2d5bea9fd85637140b62cce78ecb2fed7ad8f Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Wed, 2 Nov 2022 13:01:05 +0200 Subject: [PATCH 053/179] Create metadata.json --- apps/pisteinen/metadata.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 apps/pisteinen/metadata.json diff --git a/apps/pisteinen/metadata.json b/apps/pisteinen/metadata.json new file mode 100644 index 000000000..f1137e589 --- /dev/null +++ b/apps/pisteinen/metadata.json @@ -0,0 +1,16 @@ +{ "id": "pisteinen", + "name": "Pisteinen - Dotted watch face", + "shortName":"Pisteinen", + "version":"0.01", + "description": "A minimal digital watch face made with dots.", + "icon": "app.png", + "screenshots": [{"url":"screenshot1.png"}], + "type": "clock", + "tags": "clock", + "supports" : ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"pisteinen.app.js","url":"app.js"}, + {"name":"pisteinen.img","url":"app-icon.js","evaluate":true} + ] +} From a01d91891d7fb29555ec300e305e632adc39b0b9 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Wed, 2 Nov 2022 13:02:00 +0200 Subject: [PATCH 054/179] Add screenshot --- apps/pisteinen/screenshot1.png | Bin 0 -> 6015 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/pisteinen/screenshot1.png diff --git a/apps/pisteinen/screenshot1.png b/apps/pisteinen/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..556c004c00f3d6ad39e63c7df34c8b1c4daa3009 GIT binary patch literal 6015 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 IhSTl;0?)cS_W%F@ literal 0 HcmV?d00001 From 4a60719456ba9e104eb88fbe9ef4bfa68c74b5c0 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Wed, 2 Nov 2022 13:04:59 +0200 Subject: [PATCH 055/179] Add app.png --- apps/pisteinen/app.png | Bin 0 -> 2403 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/pisteinen/app.png diff --git a/apps/pisteinen/app.png b/apps/pisteinen/app.png new file mode 100644 index 0000000000000000000000000000000000000000..a6c441423c78d7384a5e58c9dde3c930e9c40d44 GIT binary patch literal 2403 zcmai0dsGu=7N0;BOQ|e95g%LWFt`+tCNl|;lZ*)n0VO~v4IqzNAWSC7NRo+}!34@f zup(HtThXIc>h>U&^#vjt>ro2oR`J;&ifHXo6uUlJWNTN!U03!?Kps`Qe@v45{qFtU z$9M0YR3;`Ye$#W7Cj>!nDq^Bk;2U#3QznDYRJSK;+Ev|}M zG-3=S8KP%dGmfHGtCepJ=F=7(Dv(GdC?-UOLLSiIG5ID|ZR44k04K#TM-<5r7Rt<0 zvU4UjfQ# z18qqHO-RZRfy>5OIb2~>>&R3}!|F%5#?IqOlkT^GGcrS-vlUWI6v#z5#+5dP$&g?S zL&y0^e>paK6SylrC9MJB1-mH6Acb6>XrZ-~0bq=3aU`sWmWu=uk%%Yc54!-@h67tl zn;)fSftC;h-7FCBFk!MF7{@~J;Lv%P5XUeVvr8LHk4DX^|DV2d24Ja%z*&klkS=L> zCL#>%urw?hDCZ#H2DM2iLu@<^sa5A0SR^b592iKo+00~71Z|R{&iOG=BSbFgIg=Ef z;6@6{y5J`h}lAG@(5Dn${6G@j54&AwW=*- zgbwtT42jTcDR7JVaH4ZyU@)W@KXjsnRZjx8R~Hl=pUU&lr05I54`)7ZlK{KnGq9n+ zszXP29S}yhC20aH(gJp2!Zz2x|x--fHD37ZH^);B3WPBw?$y7S;#FPvi~v5f3bPV zY5ir|&Vybe_abha{Gq$ZeYHZit(xN~{j8qr#ZB<9X6v@kjNMuFkJw4aXRLy!^yK?V z9r8cChMg3D(tUhMbQuhz#ZhAz0o8EG6;eT~itxWX?L5jD^)iFM` z6_}SiP;qO1rnZN8yRJyP!@VD=T!Z&ium2%ZK3l)8cIt+$y@;C+B`aCxdX8_!VrYa5f1t0dwB=h`nfoH$!ONZdYZlk%&S zf$Q78TwLc!U-9AwKB|bF{9yJJD)!h)UZsQcbkWc=ZI;{M#{Q+PfAhVl+kS}%%jRjWWnSvr zm(ta9GO(3fZ@fIOzTvw@+x2DoXQ%#t;6hP%>EMDTdbYc$YvJQYqGegr_eZ|Z@5=5u a)xyEe{udr;rT=#RH&R3=L^Vccm;DbE Date: Wed, 2 Nov 2022 13:05:35 +0200 Subject: [PATCH 056/179] Create app-icon.js --- apps/pisteinen/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/pisteinen/app-icon.js diff --git a/apps/pisteinen/app-icon.js b/apps/pisteinen/app-icon.js new file mode 100644 index 000000000..d8ad05c50 --- /dev/null +++ b/apps/pisteinen/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkDmYA0/4AKCpM/CxYAB+YtTGJQuOGBAWPGAwuQGAwXvCyJgFC+UhiQDNC43ygEAl4DLC4/xBYMfAZYXfI653XX/6//X/6//O5gBKU5gGBAZAXfI66//C7s/CyPzC+ZgSCwgwRFwowRCwwwPFw4xOCpIArA==")) From e7bf14b24053b8fa8d23622f98178e2d074d9de0 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Wed, 2 Nov 2022 13:06:21 +0200 Subject: [PATCH 057/179] Create README.md --- apps/pisteinen/README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 apps/pisteinen/README.md diff --git a/apps/pisteinen/README.md b/apps/pisteinen/README.md new file mode 100644 index 000000000..20e8bf9a1 --- /dev/null +++ b/apps/pisteinen/README.md @@ -0,0 +1,7 @@ +# Pisteinen + +By Jukio Kallio + +A Minimal digital watch face consisting of dots. Big dots for hours, small dots for minutes. + +![](screenshot1.png) From 92d540a6028839f4cf0832ae14392038ccc57bd7 Mon Sep 17 00:00:00 2001 From: Marco H Date: Wed, 2 Nov 2022 19:42:50 +0100 Subject: [PATCH 058/179] Initial version of Slope Clock ++ --- apps/slopeclockpp/ChangeLog | 1 + apps/slopeclockpp/app-icon.js | 1 + apps/slopeclockpp/app.js | 220 +++++++++++++++++++++++++++++++ apps/slopeclockpp/app.png | Bin 0 -> 10685 bytes apps/slopeclockpp/metadata.json | 14 ++ apps/slopeclockpp/screenshot.png | Bin 0 -> 15562 bytes 6 files changed, 236 insertions(+) create mode 100644 apps/slopeclockpp/ChangeLog create mode 100644 apps/slopeclockpp/app-icon.js create mode 100644 apps/slopeclockpp/app.js create mode 100644 apps/slopeclockpp/app.png create mode 100644 apps/slopeclockpp/metadata.json create mode 100644 apps/slopeclockpp/screenshot.png diff --git a/apps/slopeclockpp/ChangeLog b/apps/slopeclockpp/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/slopeclockpp/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/slopeclockpp/app-icon.js b/apps/slopeclockpp/app-icon.js new file mode 100644 index 000000000..bd62b928d --- /dev/null +++ b/apps/slopeclockpp/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4P/AAMA/Ayq8EH8AEBgfgj4zCj/gn/8Aod//wFDvk/gEEAoP4AoMAEIP4j4FFwAFC/gFEv//ApM/74FDg4XBgZLCFIMzAoU4g8BK4dwgMP+Ewg+AgMfK4PhAoXwh+B/0Bj0B/4FBgYnB/8B/kDgf/+ED/kHn//HgIFBW4IFB/AFDgf4h4FB+EBFgLKCAoInBAAOAAoqkBAgPAWAIuBAoXAn+zCAMB4F/8YFBgYFB4YFBRgY7BYwIoCABX4zkY74FB/mMiALC/3mug6CAAgA==")) diff --git a/apps/slopeclockpp/app.js b/apps/slopeclockpp/app.js new file mode 100644 index 000000000..25fd307eb --- /dev/null +++ b/apps/slopeclockpp/app.js @@ -0,0 +1,220 @@ +Graphics.prototype.setFontPaytoneOne = function(scale) { + // Actual height 81 (91 - 11) + this.setFontCustom( + E.toString(require('heatshrink').decompress(atob('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'))), + 46, + atob("ITZOMzs7SDxHNUdGIQ=="), + 113+(scale<<8)+(1<<16) + ); + return this; +}; + +{ // must be inside our own scope here so that when we are unloaded everything disappears + // we also define functions using 'let fn = function() {..}' for the same reason. function decls are global +let drawTimeout; + +let g2 = Graphics.createArrayBuffer(g.getWidth(),90,1,{msb:true}); +let g2img = { + width:g2.getWidth(), height:g2.getHeight(), bpp:1, + buffer:g2.buffer, transparent:0 +}; +const slope = 20; +const offsy = 20; // offset of numbers from middle +const fontBorder = 4; // offset from left/right +const slopeBorder = 10, slopeBorderUpper = 4; // fudge-factor to move minutes down from slope +let R,x,y; // middle of the clock face +let dateStr = ""; +let bgColors = g.theme.dark ? ["#ff0","#0ff","#f0f"] : ["#f00","#0f0","#00f"]; +let bgColor = bgColors[(Math.random()*bgColors.length)|0]; + + +// Draw the hour, and the minute into an offscreen buffer +let draw = function() { + R = Bangle.appRect; + x = R.w / 2; + y = R.y + R.h / 2 - 12; // 12 = room for date + var date = new Date(); + var hourStr = date.getHours(); + var minStr = date.getMinutes().toString().padStart(2,0); + dateStr = require("locale").dow(date, 1).toUpperCase()+ " "+ + require("locale").date(date, 0).toUpperCase(); + + // Draw hour + g.reset().clearRect(R); // clear whole background (w/o widgets) + g.setFontAlign(-1, 0).setFont("PaytoneOne"); + g.drawString(hourStr, fontBorder, y-offsy); + // add slope in background color + g.setColor(g.theme.bg).fillPoly([0,y+slope-slopeBorderUpper, R.w,y-slope-slopeBorderUpper, + R.w,y-slope, 0,y+slope]); + + // Draw minute to offscreen buffer + g2.setColor(0).fillRect(0,0,g2.getWidth(),g2.getHeight()).setFontAlign(1, 0).setFont("PaytoneOne"); + g2.setColor(1).drawString(minStr, g2.getWidth()-fontBorder, g2.getHeight()/2); + g2.setColor(0).fillPoly([0,0, g2.getWidth(),0, 0,slope*2]); + // start the animation *in* + animate(true); + + // queue next draw + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + animate(false, function() { + draw(); + }); + }, 60000 - (Date.now() % 60000)); +}; + +let isAnimIn = true; +let animInterval; +// Draw *just* the minute image +let drawMinute = function() { + var yo = slopeBorder + offsy + y - 2*slope*minuteX/R.w; + // draw over the slanty bit + g.setColor(bgColor).fillPoly([0,y+slope, R.w,y-slope, R.w,R.h+R.y, 0,R.h+R.y]); + // draw the minutes + g.setColor(g.theme.bg).drawImage(g2img, x+minuteX-(g2.getWidth()/2), yo-(g2.getHeight()/2)); +}; +let animate = function(isIn, callback) { + if (animInterval) clearInterval(animInterval); + isAnimIn = isIn; + minuteX = isAnimIn ? -g2.getWidth() : 0; + drawMinute(); + animInterval = setInterval(function() { + minuteX += 8; + let stop = false; + if (isAnimIn && minuteX>=0) { + minuteX=0; + stop = true; + } else if (!isAnimIn && minuteX>=R.w) + stop = true; + drawMinute(); + if (stop) { + clearInterval(animInterval); + animInterval=undefined; + if (isAnimIn) { + // draw the date + g.setColor(g.theme.bg).setFontAlign(0, 0).setFont("6x15").drawString(dateStr, R.x + R.w/2, R.y+R.h-9); + + // draw steps to bottom left + const steps = getSteps(); + if (steps > 0) + g.setFontAlign(-1, 0).drawString(shortValue(steps), 3, R.y+R.h-30); + + // draw weather to top right + const weather = getWeather(); + const tempString = weather ? require("locale").temp(weather.temp - 273.15) : undefined; + const code = weather ? weather.code : -1; + if (code > -1) { + g.setColor(g.theme.fg).setFontAlign(1, 0).drawString(tempString, R.w - 3, y-slope-slopeBorderUpper); + const icon = getWeatherIconByCode(code); + if (icon) g.drawImage(icon, R.w - 3 - 15, y-slope-slopeBorderUpper - 15 - 15); + } + } + if (callback) callback(); + } + }, 20); +}; + +let getSteps = function() { + if (Bangle.getHealthStatus) { + return Bangle.getHealthStatus("day").steps; + } + if (WIDGETS && WIDGETS.wpedom !== undefined) { + return WIDGETS.wpedom.getSteps(); + } + return 0; +}; + +let shortValue = function(v) { + if (isNaN(v)) return '-'; + if (v <= 999) return v; + if (v >= 1000 && v < 10000) { + v = Math.floor(v / 100) * 100; + return (v / 1000).toFixed(1).replace(/\.0$/, '') + 'k'; + } + if (v >= 10000) { + v = Math.floor(v / 1000) * 1000; + return (v / 1000).toFixed(1).replace(/\.0$/, '') + 'k'; + } +}; + +let getWeather = function() { + let jsonWeather = require("Storage").readJSON('weather.json'); + return jsonWeather && jsonWeather.weather ? jsonWeather.weather : undefined; +}; + +/* + * Choose weather icon to display based on weather conditition code + * https://openweathermap.org/weather-conditions#Weather-Condition-Codes-2 + */ +let getWeatherIconByCode = function(code) { + let codeGroup = Math.round(code / 100); + + // weather icons: + let weatherCloudy = atob("EBCBAAAAAAAAAAfgD/Af8H/4//7///////9//z/+AAAAAAAA"); + let weatherSunny = atob("EBCBAAAAAYAQCBAIA8AH4A/wb/YP8A/gB+ARiBAIAYABgAAA"); + let weatherMoon = atob("EBCBAAAAAYAP8B/4P/w//D/8f/5//j/8P/w//B/4D/ABgAAA"); + let weatherPartlyCloudy = atob("EBCBAAAAAAAYQAMAD8AIQBhoW+AOYBwwOBBgHGAGP/wf+AAA"); + let weatherRainy = atob("EBCBAAAAAYAH4AwwOBBgGEAOQAJBgjPOEkgGYAZgA8ABgAAA"); + let weatherPartlyRainy = atob("EBCBAAAAEEAQAAeADMAYaFvoTmAMMDgQIBxhhiGGG9wDwAGA"); + let weatherSnowy = atob("EBCBAAAAAAADwAGAEYg73C50BCAEIC50O9wRiAGAA8AAAAAA"); + let weatherFoggy = atob("EBCBAAAAAAADwAZgDDA4EGAcQAZAAgAAf74AAAAAd/4AAAAA"); + let weatherStormy = atob("EBCBAAAAAYAH4AwwOBBgGEAOQMJAgjmOGcgAgACAAAAAAAAA"); + let unknown = undefined; + + switch (codeGroup) { + case 2: + return weatherStormy; + case 3: + return weatherCloudy; + case 5: + switch (code) { + case 511: + return weatherSnowy; + case 520: + return weatherPartlyRainy; + case 521: + return weatherPartlyRainy; + case 522: + return weatherPartlyRainy; + case 531: + return weatherPartlyRainy; + default: + return weatherRainy; + } + case 6: + return weatherSnowy; + case 7: + return weatherFoggy; + case 8: + switch (code) { + case 800: + return weatherSunny; + case 801: + return weatherPartlyCloudy; + case 802: + return weatherPartlyCloudy; + default: + return weatherCloudy; + } + default: + return unknown; + } +} + +// Show launcher when middle button pressed +Bangle.setUI({ + mode : "clock", + remove : function() { + // Called to unload all of the clock app + if (animInterval) clearInterval(animInterval); + animInterval = undefined; + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + delete Graphics.prototype.setFontPaytoneOne; + }}); +// Load widgets +Bangle.loadWidgets(); +draw(); +setTimeout(Bangle.drawWidgets,0); +} diff --git a/apps/slopeclockpp/app.png b/apps/slopeclockpp/app.png new file mode 100644 index 0000000000000000000000000000000000000000..2f5912fcf3c5dde259cd3f6ec1f7745cd3013d8e GIT binary patch literal 10685 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%0A^TaIdNAA1c|vojMSZS%LP3!g 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 ZwI=CXS3MV047Msb8n<;-%5L2c`9H>$Z?^yd literal 0 HcmV?d00001 diff --git a/apps/slopeclockpp/metadata.json b/apps/slopeclockpp/metadata.json new file mode 100644 index 000000000..9e28424a8 --- /dev/null +++ b/apps/slopeclockpp/metadata.json @@ -0,0 +1,14 @@ +{ "id": "slopeclockpp", + "name": "Slope Clock ++", + "version":"0.01", + "description": "A clock where hours and minutes are divided by a sloping line. When the minute changes, the numbers slide off the screen. This is a clone of the original Slope Clock which shows weather and steps.", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "clock", + "tags": "clock", + "supports" : ["BANGLEJS2"], + "storage": [ + {"name":"slopeclockpp.app.js","url":"app.js"}, + {"name":"slopeclockpp.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/slopeclockpp/screenshot.png b/apps/slopeclockpp/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..93970956c17750f51c2281a8ee7f483b737b0468 GIT binary patch literal 15562 zcmeI0TZ$_;5QZHH_$4p%G@Ch3!C(kvFE$u@TUkdoHK~iL>Mvbv^~EP4OwT!PsV<*> zm85RZ{Ql?PKTdM}L7%_T|G((xm(#Co`;z}(a{Hp*7hfa$<@@@7Rp4=XERW0O`nW91 zW4T3PMFtIRi7{(noUR^ilF+B&HK2lPsS-+!jXw* zqaJZje=vkHsSKL^xSC$(s(BBWX`(l{SK_L9Lm?gyohboC7WHWa9fUk;-XPextd?aV zmsd~C>jf`Y)oa{E#H!x?TwXP01((WO%<7rm3KB>;<-GAR<9YLW6B60!7*bC?>$u<1 z-xb(V0ojYI^B22Dne+--ebIXdu3kDv^z2V>Mpl~rPp(spUo#3rNd8dezUY5ey4XX40JadwXNKK?%o0?U06vR z&UUp|>3JhF83gg@T*XB})*f(iJP7GGjRkkqg?jgLlK>bG>z-nI9n8}<%FW*mv!_Q3 zTgwd}x3CbqxK%Q8*A%$cTVa#lJ=|Oc>fylkpiOWXFpb*buoebv=eC(x;MQxSH+Pi7 z?Ir-Z#S7nNns77J+!l-xn#Gn^(lJZgO#()!vsg@8_l{XBxt*e=AyNg~V00(FEF*#1 zPMaGs=u=LbV^g=t=2oxhS*{)8pd8inj8h|gS{Iguc)%OxO}<0Tidd>SUWOn%7)4manxPEGT}I%K&d7{+Pqa9()d zz)O6{1&lUfpb_`HfCm9#1_}mfJHl+_wamHb+a1BtUm>Idn zhGYvf>~f>W2mQP}Z^*S|05@EV!8^qJ^8vWdfH=1yr*1>MbHV1}VEYeqL)x)=-_C`l zY#%$m2+)A}b=J-G{(D?H9OYsS_}<#5H*>KJ9j@0B;#`;MJ?J`0Z81=(#`Qa%E6i2fGfA>4;u!q6Mg>DsJ%m6I10GQ zL~ul}XeprK#-g^a74&{+JgEBqZ)>i={WJHs^=xnQitD1@Kemx_7H&a3-}gfVuCxJL+%zxeRqlorx@U*5sJf8LL;0~h7v4eQ3-`^OQ>M!#nBtA_va%bPxyk5B&G zdkKpF=0JzyXzq@^Rq05mz1!%sq0S(W1#ihiiS@xrmk5H9YFPwcH~% W@VlOq?|QCB6|8l{)67^u?fwsI8A4G2 literal 0 HcmV?d00001 From 5e525f081fbd3ae740503945b9823603eb89600f Mon Sep 17 00:00:00 2001 From: Bruce Blore Date: Wed, 2 Nov 2022 12:06:17 -0700 Subject: [PATCH 059/179] Added bgtimer, gallery, infoclk, pomoplus, random, rpnsci, stlap, stlapview bgtimer: A timer that runs in the background and can be set with a keypad gallery: An app to present a list of images in a menu and allow the user to pick from them infoclk: A clock face that displays more information and some app shortcuts when unlocked pomoplus: A configurable pomodoro timer that runs in the background random: Random number generator rpnsci: Scientific calculator using reverse polish notation stlap: A stopwatch with lap timer that runs in the background stlapview: An optional app that displays data collected by stlap --- apps/bgtimer/app.js | 27 ++ apps/bgtimer/boot.js | 11 + apps/bgtimer/common.js | 42 +++ apps/bgtimer/icon.js | 1 + apps/bgtimer/icon.png | Bin 0 -> 414 bytes apps/bgtimer/img/pause.png | Bin 0 -> 2891 bytes apps/bgtimer/img/play.png | Bin 0 -> 2891 bytes apps/bgtimer/img/reset.png | Bin 0 -> 2891 bytes apps/bgtimer/keypad.js | 136 +++++++++ apps/bgtimer/metadata.json | 44 +++ apps/bgtimer/ring.js | 28 ++ apps/bgtimer/timerview.js | 107 +++++++ apps/gallery/README.md | 18 ++ apps/gallery/app.js | 52 ++++ apps/gallery/icon.js | 1 + apps/gallery/icon.png | Bin 0 -> 249 bytes apps/gallery/metadata.json | 26 ++ apps/infoclk/README.md | 33 ++ apps/infoclk/app.js | 405 +++++++++++++++++++++++++ apps/infoclk/font.js | 23 ++ apps/infoclk/font/am.png | Bin 0 -> 360 bytes apps/infoclk/font/colon.png | Bin 0 -> 216 bytes apps/infoclk/font/digit0.png | Bin 0 -> 290 bytes apps/infoclk/font/digit1.png | Bin 0 -> 183 bytes apps/infoclk/font/digit2.png | Bin 0 -> 305 bytes apps/infoclk/font/digit3.png | Bin 0 -> 270 bytes apps/infoclk/font/digit4.png | Bin 0 -> 247 bytes apps/infoclk/font/digit5.png | Bin 0 -> 302 bytes apps/infoclk/font/digit6.png | Bin 0 -> 309 bytes apps/infoclk/font/digit7.png | Bin 0 -> 227 bytes apps/infoclk/font/digit8.png | Bin 0 -> 309 bytes apps/infoclk/font/digit9.png | Bin 0 -> 319 bytes apps/infoclk/font/pm.png | Bin 0 -> 327 bytes apps/infoclk/icon.js | 2 + apps/infoclk/icon.png | Bin 0 -> 1989 bytes apps/infoclk/metadata.json | 38 +++ apps/infoclk/settings.js | 571 +++++++++++++++++++++++++++++++++++ apps/pomoplus/app.js | 157 ++++++++++ apps/pomoplus/boot.js | 19 ++ apps/pomoplus/common.js | 118 ++++++++ apps/pomoplus/icon.js | 1 + apps/pomoplus/icon.png | Bin 0 -> 2122 bytes apps/pomoplus/img/pause.png | Bin 0 -> 2891 bytes apps/pomoplus/img/play.png | Bin 0 -> 2891 bytes apps/pomoplus/img/reset.png | Bin 0 -> 2891 bytes apps/pomoplus/img/skip.png | Bin 0 -> 2891 bytes apps/pomoplus/metadata.json | 37 +++ apps/pomoplus/settings.js | 94 ++++++ apps/random/app.js | 205 +++++++++++++ apps/random/icon.js | 1 + apps/random/icon.png | Bin 0 -> 378 bytes apps/random/metadata.json | 24 ++ apps/rpnsci/README.md | 38 +++ apps/rpnsci/app.js | 403 ++++++++++++++++++++++++ apps/rpnsci/icon.js | 1 + apps/rpnsci/icon.png | Bin 0 -> 765 bytes apps/rpnsci/icon.xcf | Bin 0 -> 4021 bytes apps/rpnsci/metadata.json | 24 ++ apps/stlap/app.js | 304 +++++++++++++++++++ apps/stlap/icon.js | 1 + apps/stlap/icon.png | Bin 0 -> 1566 bytes apps/stlap/img/pause.png | Bin 0 -> 2891 bytes apps/stlap/img/play.png | Bin 0 -> 2891 bytes apps/stlap/img/reset.png | Bin 0 -> 2891 bytes apps/stlap/metadata.json | 24 ++ apps/stlapview/app.js | 110 +++++++ apps/stlapview/icon.js | 1 + apps/stlapview/icon.png | Bin 0 -> 1566 bytes apps/stlapview/metadata.json | 27 ++ 69 files changed, 3154 insertions(+) create mode 100644 apps/bgtimer/app.js create mode 100644 apps/bgtimer/boot.js create mode 100644 apps/bgtimer/common.js create mode 100644 apps/bgtimer/icon.js create mode 100644 apps/bgtimer/icon.png create mode 100644 apps/bgtimer/img/pause.png create mode 100644 apps/bgtimer/img/play.png create mode 100644 apps/bgtimer/img/reset.png create mode 100644 apps/bgtimer/keypad.js create mode 100644 apps/bgtimer/metadata.json create mode 100644 apps/bgtimer/ring.js create mode 100644 apps/bgtimer/timerview.js create mode 100644 apps/gallery/README.md create mode 100644 apps/gallery/app.js create mode 100644 apps/gallery/icon.js create mode 100644 apps/gallery/icon.png create mode 100644 apps/gallery/metadata.json create mode 100644 apps/infoclk/README.md create mode 100644 apps/infoclk/app.js create mode 100644 apps/infoclk/font.js create mode 100644 apps/infoclk/font/am.png create mode 100644 apps/infoclk/font/colon.png create mode 100644 apps/infoclk/font/digit0.png create mode 100644 apps/infoclk/font/digit1.png create mode 100644 apps/infoclk/font/digit2.png create mode 100644 apps/infoclk/font/digit3.png create mode 100644 apps/infoclk/font/digit4.png create mode 100644 apps/infoclk/font/digit5.png create mode 100644 apps/infoclk/font/digit6.png create mode 100644 apps/infoclk/font/digit7.png create mode 100644 apps/infoclk/font/digit8.png create mode 100644 apps/infoclk/font/digit9.png create mode 100644 apps/infoclk/font/pm.png create mode 100644 apps/infoclk/icon.js create mode 100644 apps/infoclk/icon.png create mode 100644 apps/infoclk/metadata.json create mode 100644 apps/infoclk/settings.js create mode 100644 apps/pomoplus/app.js create mode 100644 apps/pomoplus/boot.js create mode 100644 apps/pomoplus/common.js create mode 100644 apps/pomoplus/icon.js create mode 100644 apps/pomoplus/icon.png create mode 100644 apps/pomoplus/img/pause.png create mode 100644 apps/pomoplus/img/play.png create mode 100644 apps/pomoplus/img/reset.png create mode 100644 apps/pomoplus/img/skip.png create mode 100644 apps/pomoplus/metadata.json create mode 100644 apps/pomoplus/settings.js create mode 100644 apps/random/app.js create mode 100644 apps/random/icon.js create mode 100644 apps/random/icon.png create mode 100644 apps/random/metadata.json create mode 100644 apps/rpnsci/README.md create mode 100644 apps/rpnsci/app.js create mode 100644 apps/rpnsci/icon.js create mode 100644 apps/rpnsci/icon.png create mode 100644 apps/rpnsci/icon.xcf create mode 100644 apps/rpnsci/metadata.json create mode 100644 apps/stlap/app.js create mode 100644 apps/stlap/icon.js create mode 100644 apps/stlap/icon.png create mode 100644 apps/stlap/img/pause.png create mode 100644 apps/stlap/img/play.png create mode 100644 apps/stlap/img/reset.png create mode 100644 apps/stlap/metadata.json create mode 100644 apps/stlapview/app.js create mode 100644 apps/stlapview/icon.js create mode 100644 apps/stlapview/icon.png create mode 100644 apps/stlapview/metadata.json diff --git a/apps/bgtimer/app.js b/apps/bgtimer/app.js new file mode 100644 index 000000000..66f22a7a2 --- /dev/null +++ b/apps/bgtimer/app.js @@ -0,0 +1,27 @@ +Bangle.BGTIMER_ACTIVE = true; +const common = require("bgtimer-com.js"); +const storage = require("Storage"); + +const keypad = require("bgtimer-keys.js"); +const timerView = require("bgtimer-tview.js"); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +//Save our state when the app is closed +E.on('kill', () => { + storage.writeJSON(common.STATE_PATH, common.state); +}); + +//Handle touch here. I would implement these separately in each view, but I can't figure out how to clear the event listeners. +Bangle.on('touch', (button, xy) => { + if (common.state.wasRunning) timerView.touch(button, xy); + else keypad.touch(button, xy); +}); + +Bangle.on('swipe', dir => { + if (!common.state.wasRunning) keypad.swipe(dir); +}); + +if (common.state.wasRunning) timerView.show(common); +else keypad.show(common); diff --git a/apps/bgtimer/boot.js b/apps/bgtimer/boot.js new file mode 100644 index 000000000..67840b3ce --- /dev/null +++ b/apps/bgtimer/boot.js @@ -0,0 +1,11 @@ +const BGTIMER_common = require("bgtimer-com.js"); + +//Only start the timeout if the timer is running +if (BGTIMER_common.state.running) { + setTimeout(() => { + //Check now to avoid race condition + if (Bangle.BGTIMER_ACTIVE === undefined) { + load('bgtimer-ring.js'); + } + }, BGTIMER_common.getTimeLeft()); +} \ No newline at end of file diff --git a/apps/bgtimer/common.js b/apps/bgtimer/common.js new file mode 100644 index 000000000..67a6660d3 --- /dev/null +++ b/apps/bgtimer/common.js @@ -0,0 +1,42 @@ +const storage = require("Storage"); +const heatshrink = require("heatshrink"); + +exports.STATE_PATH = "bgtimer.state.json"; + +exports.BUTTON_ICONS = { + play: heatshrink.decompress(atob("jEYwMAkAGBnACBnwCBn+AAQPgAQPwAQP8AQP/AQXAAQPwAQP8AQP+AQgICBwQUCEAn4FggyBHAQ+CIgQ")), + pause: heatshrink.decompress(atob("jEYwMA/4BBAX4CEA")), + reset: heatshrink.decompress(atob("jEYwMA/4BB/+BAQPDAQPnAQIAKv///0///8j///EP//wAQQICBwQUCEhgyCHAQ+CIgI=")) +}; + +//Store the minimal amount of information to be able to reconstruct the state of the timer at any given time. +//This is necessary because it is necessary to write to flash to let the timer run in the background, so minimizing the writes is necessary. +exports.STATE_DEFAULT = { + wasRunning: false, //If the timer ever was running. Used to determine whether to display a reset button + running: false, //Whether the timer is currently running + startTime: 0, //When the timer was last started. Difference between this and now is how long timer has run continuously. + pausedTime: 0, //When the timer was last paused. Used for expiration and displaying timer while paused. + elapsedTime: 0, //How much time the timer had spent running before the current start time. Update on pause or user skipping stages. + setTime: 0, //How long the user wants the timer to run for + inputString: '0' //The string of numbers the user typed in. +}; +exports.state = storage.readJSON(exports.STATE_PATH); +if (!exports.state) { + exports.state = exports.STATE_DEFAULT; +} + +//Get the number of milliseconds until the timer expires +exports.getTimeLeft = function () { + if (!exports.state.wasRunning) { + //If the timer never ran, the time left is just the set time + return exports.setTime + } else if (exports.state.running) { + //If the timer is running, the time left is current time - start time + preexisting time + var runningTime = (new Date()).getTime() - exports.state.startTime + exports.state.elapsedTime; + } else { + //If the timer is not running, the same as above but use when the timer was paused instead of now. + var runningTime = exports.state.pausedTime - exports.state.startTime + exports.state.elapsedTime; + } + + return exports.state.setTime - runningTime; +} \ No newline at end of file diff --git a/apps/bgtimer/icon.js b/apps/bgtimer/icon.js new file mode 100644 index 000000000..a47eb21f8 --- /dev/null +++ b/apps/bgtimer/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwcAkmSpICOggRPpEACJ9AgESCJxMBhu27dtARVgCIMBCJpxDmwRL7ARDgwRL4CWECJaoFjYRJ2ARFgYRJwDNGCJFsb46SIRgQAFSRAQHSRCMEAAqSGRgoAFRhaSKRgySKRg6SIRhCSIRhCSICBqSCRhSSGRhY2FkARPhMkCJ9JkiONgECCIOQCJsSCIOSCJuSCIVACBcECIdICJYOBCIVJRhYRFSRSMBCIiSKBwgCCSRCMCCIqSIRgYCFRhYCFSQyMEAQqSGBw6SIRgySKRgtO4iSJBAmT23bOIqSCRgvtCINsSQ4aEndtCINt2KSGIggOBCIW2JQlARgZECCIhKEpBEGCIpKEA==")) \ No newline at end of file diff --git a/apps/bgtimer/icon.png b/apps/bgtimer/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7dcf44b88254d3f31f6c94d8d3f4933fc2f1f3ec GIT binary patch literal 414 zcmV;P0b%}$P)S|NQ$gCcl(vO0I@(u75S@S(5l8z2uoB`P_zbWw zrm4RZMDIcW0M2=s5|PIQSAQ9GhHvoa~#6ticgf|`rupkieP=E%3iiZOv2xNQ+ zpoT!lhXFW5M0_aViHM312i)5=&)tvz$Ko#bnHY2Xe6J}65d|BRBpJU;*HZzryneBR}MeU;y^`QaBd! zMnDd_rQtXTd(f>Pd22WZ@_N-k7mo_}L-v@ literal 0 HcmV?d00001 diff --git a/apps/bgtimer/img/pause.png b/apps/bgtimer/img/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..ad31dadcff3ecffba6c7e015a4b2ecdcccc15b0f GIT binary patch literal 2891 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x}o+U~I{Bb`J1#c2+1T%1_J8No8Qr zm{>c}*5j~)%+dJZrAngg+8q`tEBwU%ILU0~a$O;i)fy)2qxZK-jn}iQd+~#)f)B|X zUp;uVW_9yw1&+D~3oA>_T^^nPy}5LgY%Ja#-(B6mySyPl-}vk+31*YKX2G31W}IBt zwJ@CJV!yyKLuKRBGbS%lsX2b#mZ@fM_eY)o#r1u1rs;+X3PR_N4sYo+?^tf0+x*$C zuthX=>W?`USC()K*%!rr{Lx!{Ftst=?MzA5JPRisv0D+D$zdj@k2D{xSoLy>eu_<) zWq#qcQ=!-PsMjZ2EMKovJolM^P{a`-m5zV_SI*QM9T!(kPEvIJT`2#5!RzTKmQGmB z;?~C+vcR$I?}PdeyQ8)3Eg!13K6ZHC{kVpQd135=z~VXYlaFW4VK|unz$^c!c4@-1 z$zP(pyX6@7-ac@&)I0cF!)e)s2PY@^-kjQG(pn=|VZS*46jSYXhwrnlM;FU4=XaR3 z%j+Hkd;0;8#!c62@7=w6@Am%mS%3dB99mg)Jm;_40${YTC3(BM0BIoj>AbrhNO2Z; zL>4nJ=qZCRW5rVYGN2%PiKnkC`!i-yb}Jpb3EHthA;}Wgh!W@g+}zZ>5(ej@)Wnk1 z6ovB4k_-iRPv3y>Mm}+%S<0R+jv*erj1rvBzcKy?0-#2mfDs6AN&+Pa>1V>HnHqAV z77z@@(I6TPB7z}6P{C*_8Vw?XAwW>UXet^FB7z}6Pyx+TQT{Ft9Zp`Z43JAaUHx3v IIVCg!009H(%m4rY literal 0 HcmV?d00001 diff --git a/apps/bgtimer/img/play.png b/apps/bgtimer/img/play.png new file mode 100644 index 0000000000000000000000000000000000000000..6c20c24c54d72382a69d5aa3685e3ad8fa6174ba GIT binary patch literal 2891 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x}o+U~I{Bb`J1#c2+1T%1_J8No8Qr zm{>c}*5j~)%+dJZrAngg+8q`tEBwU%ILU0~a$O;i)fy)2qxZK-jn}iQd+~#)f)B|X zUp;uVW_9yw1&+D~3oA>_T^^nPy}5LgY%Ja#-(B6mySyPl-}vk+31*YKX2G31W}IBt zwJ@CJV!yyKLuKRBGbS%lsX2b#mZ@fM_eY)o#r1u1rs;+X3PR_N4sYo+?^tf0+x*$C zuthX=>W?`USC()K*%!rr{Lx!{Ftst=?MzA5JPRisv0D+D$zdj@k2D{xSoLy>eu_<) zWq#qcQ=!-PsMjZ2EMKovJolM^P{a`-m5zV_SI*QM9T!(kPEvIJT`2#5!RzTKmQGmB z;?~C+vcR$I?}PdeyQ8)3Eg!13K6ZHC{kVpQd135=z~VXYlaFW4VK|unz$^c!c4@-1 z$zP(pyX6@7-ac@&)I0cF!)e)s2PY@^-kjQG(pn=|VZS*46jSYXhwrnlM;FU4=XaR3 z%j+Hkd;0;8#!c62@7=w6@Am%mS%3dB99mg)Jm;_40${YTC3(BM0BIoj>AbrhNO2Z; zL>4nJ=qZCRW5rVYGN2%PiKnkC`!i-yc1y0~8~!E(g(OQ{BTAg}b8}PkN*J7rQWHy3 zQxwWGOEMJPJ$(bh8~Mb6W+{8RIEHxeGD>hh{|3|p0snyj#-=9C2r~@X0!AQ!iBn3$ z4MMg6W+*i*!fOFFEF#JRN-Sc6X(ooo7L0`Sk>mqp!-$O^vMqpFM#v(HEg)nO)hxhe z5!Ed~w}_-v1k+3m4NGw}vjFA@nppr#T`Vx0s71pJhM7k-3(yUwngzHFrq}{P2E!~M zE0T#d9ApVeaX^Z}FdqmdKI;Vst0LE7sJpcdz literal 0 HcmV?d00001 diff --git a/apps/bgtimer/img/reset.png b/apps/bgtimer/img/reset.png new file mode 100644 index 0000000000000000000000000000000000000000..7a317d09795c09aabab4836c8b9ec4a6c5fe4db8 GIT binary patch literal 2891 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x}o+U~I{Bb`J1#c2+1T%1_J8No8Qr zm{>c}*5j~)%+dJZrAngg+8q`tEBwU%ILU0~a$O;i)fy)2qxZK-jn}iQd+~#)f)B|X zUp;uVW_9yw1&+D~3oA>_T^^nPy}5LgY%Ja#-(B6mySyPl-}vk+31*YKX2G31W}IBt zwJ@CJV!yyKLuKRBGbS%lsX2b#mZ@fM_eY)o#r1u1rs;+X3PR_N4sYo+?^tf0+x*$C zuthX=>W?`USC()K*%!rr{Lx!{Ftst=?MzA5JPRisv0D+D$zdj@k2D{xSoLy>eu_<) zWq#qcQ=!-PsMjZ2EMKovJolM^P{a`-m5zV_SI*QM9T!(kPEvIJT`2#5!RzTKmQGmB z;?~C+vcR$I?}PdeyQ8)3Eg!13K6ZHC{kVpQd135=z~VXYlaFW4VK|unz$^c!c4@-1 z$zP(pyX6@7-ac@&)I0cF!)e)s2PY@^-kjQG(pn=|VZS*46jSYXhwrnlM;FU4=XaR3 z%j+Hkd;0;8#!c62@7=w6@Am%mS%3dB99mg)Jm;_40${YTC3(BM0BIoj>AbrhNO2Z; zL>4nJ=qZCRW5rVYGN2%PiKnkC`!i-y4rWEypL5fJLXst}5hc#~xw)x%B@E6*sfi`2 zDGKG8B^e6tp1uL$jeO!jvy?qu978;K86`NMe`EX)1VD{A0V5FLlmto;($9oXGe{1f z0r=!#<`T33mnFm)4$@1M1?ZL#YdAG9F5Ihr6 z+Y*@Ba0@^#qn0Hw!$D@ESU?R+kPQc!NApyK;scrn5w#2l1q%qkf(q;dY8wu*0%FN% zSp*9WoHWgoDM=Q9QU(a%bS@SNqAfr+7@3X5OcWuaEWl { + common.state.inputString = '0'; + common.state.setTime = 0; + updateDisplay(); + feedback(true); + } +}; + +let StartButton = { + label: 'Go', + onclick: () => { + common.state.startTime = (new Date()).getTime(); + common.state.elapsedTime = 0; + common.state.wasRunning = true; + common.state.running = true; + feedback(true); + require('bgtimer-tview.js').show(common); + } +}; + +const BUTTONS = [ + [new NumberButton(7), new NumberButton(8), new NumberButton(9), ClearButton], + [new NumberButton(4), new NumberButton(5), new NumberButton(6), new NumberButton(0)], + [new NumberButton(1), new NumberButton(2), new NumberButton(3), StartButton] +]; + +function feedback(acceptable) { + if (acceptable) Bangle.buzz(50, 0.5); + else Bangle.buzz(200, 1); +} + +function drawButtons() { + g.reset().clearRect(0, 44, 175, 175).setFont("Vector", 15).setFontAlign(0, 0); + //Draw lines + for (let x = 44; x <= 176; x += 44) { + g.drawLine(x, 44, x, 175); + } + for (let y = 44; y <= 176; y += 44) { + g.drawLine(0, y, 175, y); + } + for (let row = 0; row < 3; row++) { + for (let col = 0; col < 4; col++) { + g.drawString(BUTTONS[row][col].label, 22 + 44 * col, 66 + 44 * row); + } + } +} + +function getFontSize(length) { + let size = Math.floor(176 / length); //Characters of width needed per pixel + size *= (20 / 12); //Convert to height + // Clamp to between 6 and 20 + if (size < 6) return 6; + else if (size > 20) return 20; + else return Math.floor(size); +} + +function updateDisplay() { + let displayString = inputStringToDisplayString(common.state.inputString); + g.clearRect(0, 24, 175, 43).setColor(storage.readJSON('setting.json').theme.fg2).setFontAlign(1, -1).setFont("Vector", getFontSize(displayString.length)).drawString(displayString, 176, 24); +} + +exports.show = function (callerCommon) { + common = callerCommon; + g.reset(); + drawButtons(); + updateDisplay(); +}; + +exports.touch = function (button, xy) { + let row = Math.floor((xy.y - 44) / 44); + let col = Math.floor(xy.x / 44); + if (row < 0) return; + if (row > 2) row = 2; + if (col < 0) col = 0; + if (col > 3) col = 3; + + BUTTONS[row][col].onclick(); +}; + +exports.swipe = function (dir) { + if (dir == -1) { + if (common.state.inputString.length == 1) common.state.inputString = '0'; + else common.state.inputString = common.state.inputString.substring(0, common.state.inputString.length - 1); + + common.state.setTime = inputStringToTime(common.state.inputString); + + feedback(true); + updateDisplay(); + } else if (dir == 0) { + EnterButton.onclick(); + } +}; \ No newline at end of file diff --git a/apps/bgtimer/metadata.json b/apps/bgtimer/metadata.json new file mode 100644 index 000000000..3f63d0ec5 --- /dev/null +++ b/apps/bgtimer/metadata.json @@ -0,0 +1,44 @@ +{ + "id": "bgtimer", + "name": "Timer", + "version": "0.02", + "description": "A timer with a keypad that runs in the background", + "icon": "icon.png", + "type": "app", + "tags": "tools", + "supports": [ + "BANGLEJS2" + ], + "allow_emulator": true, + "storage": [ + { + "name": "bgtimer.app.js", + "url": "app.js" + }, + { + "name": "bgtimer.img", + "url": "icon.js", + "evaluate": true + }, + { + "name": "bgtimer.boot.js", + "url": "boot.js" + }, + { + "name": "bgtimer-com.js", + "url": "common.js" + }, + { + "name": "bgtimer-ring.js", + "url": "ring.js" + }, + { + "name": "bgtimer-keys.js", + "url": "keypad.js" + }, + { + "name": "bgtimer-tview.js", + "url": "timerview.js" + } + ] +} \ No newline at end of file diff --git a/apps/bgtimer/ring.js b/apps/bgtimer/ring.js new file mode 100644 index 000000000..9df5cb4bd --- /dev/null +++ b/apps/bgtimer/ring.js @@ -0,0 +1,28 @@ +const common = require('bgtimer-com.js'); + +Bangle.loadWidgets() +Bangle.drawWidgets() + +Bangle.setLocked(false); +Bangle.setLCDPower(true); + +let brightness = 0; + +setInterval(() => { + Bangle.buzz(200); + Bangle.setLCDBrightness(1 - brightness); + brightness = 1 - brightness; +}, 400); +Bangle.buzz(200); + +function stopTimer() { + common.state.wasRunning = false; + common.state.running = false; + require("Storage").writeJSON(common.STATE_PATH, common.state); +} + +E.showAlert("Timer expired!").then(() => { + stopTimer(); + load(); +}); +E.on('kill', stopTimer); \ No newline at end of file diff --git a/apps/bgtimer/timerview.js b/apps/bgtimer/timerview.js new file mode 100644 index 000000000..4c9f7acd3 --- /dev/null +++ b/apps/bgtimer/timerview.js @@ -0,0 +1,107 @@ +let common; + +function drawButtons() { + //Draw the backdrop + const BAR_TOP = g.getHeight() - 24; + g.setColor(0, 0, 1).setFontAlign(0, -1) + .clearRect(0, BAR_TOP, g.getWidth(), g.getHeight()) + .fillRect(0, BAR_TOP, g.getWidth(), g.getHeight()) + .setColor(1, 1, 1) + .drawLine(g.getWidth() / 2, BAR_TOP, g.getWidth() / 2, g.getHeight()) + + //Draw the buttons + .drawImage(common.BUTTON_ICONS.reset, g.getWidth() / 4, BAR_TOP); + if (common.state.running) { + g.drawImage(common.BUTTON_ICONS.pause, g.getWidth() * 3 / 4, BAR_TOP); + } else { + g.drawImage(common.BUTTON_ICONS.play, g.getWidth() * 3 / 4, BAR_TOP); + } +} + +function drawTimer() { + let timeLeft = common.getTimeLeft(); + g.reset() + .setFontAlign(0, 0) + .setFont("Vector", 36) + .clearRect(0, 24, 176, 152) + + //Draw the timer + .drawString((() => { + let hours = timeLeft / 3600000; + let minutes = (timeLeft % 3600000) / 60000; + let seconds = (timeLeft % 60000) / 1000; + + function pad(number) { + return ('00' + parseInt(number)).slice(-2); + } + + if (hours >= 1) return `${parseInt(hours)}:${pad(minutes)}:${pad(seconds)}`; + else return `${parseInt(minutes)}:${pad(seconds)}`; + })(), g.getWidth() / 2, g.getHeight() / 2) + + if (timeLeft <= 0) load('bgtimer-ring.js'); +} + +let timerInterval; + +function setupTimerInterval() { + if (timerInterval !== undefined) { + clearInterval(timerInterval); + } + setTimeout(() => { + timerInterval = setInterval(drawTimer, 1000); + drawTimer(); + }, common.timeLeft % 1000); +} + +exports.show = function (callerCommon) { + common = callerCommon; + drawButtons(); + drawTimer(); + if (common.state.running) { + setupTimerInterval(); + } +} + +function clearTimerInterval() { + if (timerInterval !== undefined) { + clearInterval(timerInterval); + timerInterval = undefined; + } +} + +exports.touch = (button, xy) => { + if (xy.y < 152) return; + + if (button == 1) { + //Reset the timer + let setTime = common.state.setTime; + let inputString = common.state.inputString; + common.state = common.STATE_DEFAULT; + common.state.setTime = setTime; + common.state.inputString = inputString; + clearTimerInterval(); + require('bgtimer-keys.js').show(common); + } else { + if (common.state.running) { + //Record the exact moment that we paused + let now = (new Date()).getTime(); + common.state.pausedTime = now; + + //Stop the timer + common.state.running = false; + clearTimerInterval(); + drawTimer(); + drawButtons(); + } else { + //Start the timer and record when we started + let now = (new Date()).getTime(); + common.state.elapsedTime += common.state.pausedTime - common.state.startTime; + common.state.startTime = now; + common.state.running = true; + drawTimer(); + setupTimerInterval(); + drawButtons(); + } + } +}; \ No newline at end of file diff --git a/apps/gallery/README.md b/apps/gallery/README.md new file mode 100644 index 000000000..b70fa07c2 --- /dev/null +++ b/apps/gallery/README.md @@ -0,0 +1,18 @@ +# Gallery + +A simple gallery app + +## Usage + +Upon opening the gallery app, you will be presented with a list of images that you can display. Tap the image to show it. Brightness will be set to full, and the screen timeout will be disabled. When you are done viewing the image, you can tap the screen to go back to the list of images. Press BTN1 to flip the image upside down. + +## Adding images + +1. The gallery app does not perform any scaling, and does not support panning. Therefore, you should use your favorite image editor to produce an image of the appropriate size for your watch. (240x240 for Bangle 1 or 176x176 for Bangle 2.) How you achieve this is up to you. If on a Bangle 2, I recommend adjusting the colors here to comply with the color restrictions. + +2. Upload your image to the [Espruino image converter](https://www.espruino.com/Image+Converter). I recommend enabling compression and choosing one of the following color settings: + * 16 bit RGB565 for Bangle 1 + * 3 bit RGB for Bangle 2 + * 1 bit black/white for monochrome images that you want to respond to your system theme. (White will be rendered as your foreground color and black will be rendered as your background color.) + +3. Set the output format to an image string, copy it into the [IDE](https://www.espruino.com/ide/), and set the destination to a file in storage. The file name should begin with "gal-" (without the quotes) and end with ".img" (without the quotes) to appear in the gallery. Note that the gal- prefix and .img extension will be removed in the UI. Upload the file. \ No newline at end of file diff --git a/apps/gallery/app.js b/apps/gallery/app.js new file mode 100644 index 000000000..ca9392f13 --- /dev/null +++ b/apps/gallery/app.js @@ -0,0 +1,52 @@ +const storage = require('Storage'); + +let imageFiles = storage.list(/^gal-.*\.img/).sort(); + +let imageMenu = { '': { 'title': 'Gallery' } }; + +for (let fileName of imageFiles) { + let displayName = fileName.substr(4, fileName.length - 8); // Trim off the 'gal-' and '.img' for a friendly display name + imageMenu[displayName] = eval(`() => { drawImage("${fileName}"); }`); // Unfortunately, eval is the only reasonable way to do this +} + +let cachedOptions = Bangle.getOptions(); // We will change the backlight and timeouts later, and need to restore them when displaying the menu +let backlightSetting = storage.readJSON('setting.json').brightness; // LCD brightness is not included in there for some reason + +let angle = 0; // Store the angle of rotation +let image; // Cache the image here because we access it in multiple places + +function drawMenu() { + Bangle.removeListener('touch', drawMenu); // We no longer want touching to reload the menu + Bangle.setOptions(cachedOptions); // The drawImage function set no timeout, undo that + Bangle.setLCDBrightness(backlightSetting); // Restore backlight + image = undefined; // Delete the image from memory + + E.showMenu(imageMenu); +} + +function drawImage(fileName) { + E.showMenu(); // Remove the menu to prevent it from breaking things + setTimeout(() => { Bangle.on('touch', drawMenu); }, 300); // Touch the screen to go back to the image menu (300ms timeout to allow user to lift finger) + Bangle.setOptions({ // Disable display power saving while showing the image + lockTimeout: 0, + lcdPowerTimeout: 0, + backlightTimeout: 0 + }); + Bangle.setLCDBrightness(1); // Full brightness + + image = eval(storage.read(fileName)); // Sadly, the only reasonable way to do this + g.clear().reset().drawImage(image, 88, 88, { rotate: angle }); +} + +setWatch(info => { + if (image) { + if (angle == 0) angle = Math.PI; + else angle = 0; + Bangle.buzz(); + + g.clear().reset().drawImage(image, 88, 88, { rotate: angle }) + } +}, BTN1, { repeat: true }); + +// We don't load the widgets because there is no reasonable way to unload them +drawMenu(); \ No newline at end of file diff --git a/apps/gallery/icon.js b/apps/gallery/icon.js new file mode 100644 index 000000000..11fee53eb --- /dev/null +++ b/apps/gallery/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgIOLgf/AAX8Av4FBJgkMAos/CIfMAv4Fe4AF/Apq5EAAw")) \ No newline at end of file diff --git a/apps/gallery/icon.png b/apps/gallery/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..71835e93da29808335d7f39c2ca849373b083d94 GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpUt1D-C9AsNnZXE|~mP~c&C{9iuz z8E5bbG@o`agQ-${dF&4QA(@#tDiuj)}sXJrCW}qOH(Be|C&4}kl zK$oM0z`>iR3=*6**%BRC(zUIR9hiOMb7|FdaVe<{ykC3EQnx{~p>pFDf+|Lvz(7tMOYcx7L0GSDv!p00i_>zopr0ApiXkN^Mx literal 0 HcmV?d00001 diff --git a/apps/gallery/metadata.json b/apps/gallery/metadata.json new file mode 100644 index 000000000..89f7606aa --- /dev/null +++ b/apps/gallery/metadata.json @@ -0,0 +1,26 @@ +{ + "id": "gallery", + "name": "Gallery", + "version": "0.02", + "description": "A gallery that lets you view images uploaded with the IDE (see README)", + "readme": "README.md", + "icon": "icon.png", + "type": "app", + "tags": "tools", + "supports": [ + "BANGLEJS2", + "BANGLEJS" + ], + "allow_emulator": true, + "storage": [ + { + "name": "gallery.app.js", + "url": "app.js" + }, + { + "name": "gallery.img", + "url": "icon.js", + "evaluate": true + } + ] +} \ No newline at end of file diff --git a/apps/infoclk/README.md b/apps/infoclk/README.md new file mode 100644 index 000000000..1dd563bec --- /dev/null +++ b/apps/infoclk/README.md @@ -0,0 +1,33 @@ +# Informational clock + +A configurable clock with extra info and shortcuts when unlocked, but large time when locked + +## Information + +The clock has two different screen arrangements, depending on whether the watch is locked or unlocked. The most commonly viewed piece of information is the time, so when the watch is locked it optimizes for the time being visible at a glance without the backlight. The hours and minutes take up nearly the entire top half of the display, with the date and seconds taking up nearly the entire bottom half. The day progress bar is between them if enabled, unless configured to be on the bottom row. The bottom row can be configured to display a weather summary, step count, step count and heart rate, the daily progress bar, or nothing. + +When the watch is unlocked, it can be assumed that the backlight is on and the user is actively looking at the watch, so instead we can optimize for information density. The bottom half of the display becomes shortcuts, and the top half of the display becomes 4 rows of information (date and time, step count and heart rate, 2 line weather summary) + an optional daily progress bar. (The daily progress bar can be independently enabled when locked and unlocked.) + +Most things are self-explanatory, but the day progress bar might not be. The day progress bar is intended to show approximately how far through the day you are, in the form of a progress bar. You might want to configure it to show how far you are through your waking hours, or you might want to use it to show how far you are through your work or school day. + +## Shortcuts + +There are generally a few apps that the user uses far more frequently than the others. For example, they might use a timer, alarm clock, and calculator every day, while everything else (such as the settings app) gets used only occasionally. This clock has space for 8 apps in the bottom half of the screen only one tap away, avoiding the need to wait for the launcher to open and then scroll through it. Tapping the top of the watch opens the launcher, eliminating the need for the button (which still opens the launcher due to bangle.js conventions). There is also handling for left, right, and vertical swipes. A vertical swipe by default opens the messages app, mimicking mobile operating systems which use a swipe down to view the notification shade. + +## Configurability + +Displaying the seconds allows for more precise timing, but waking up the CPU to refresh the display more often consumes battery. The user can enable or disable them completely, but can also configure them to be enabled or disabled automatically based on some hueristics: + +* They can be hidden while the display is locked, if the user expects to unlock their watch when they need the seconds. +* They can be hidden when the battery is too low, to make the last portion of the battery last a little bit longer. +* They can be hidden during a period of time such as when the user is asleep and therefore unlikely to need very much precision. + +The date format can be changed. + +As described earlier, the contents of the bottom row when locked can be changed. + +The 8 tap-based shortcuts on the bottom and the 3 swipe-based shortcuts can be changed to nothing, the launcher, or any app on the watch. + +The start and end time of the day progress bar can be changed. It can be enabled or disabled separately when the watch is locked and unlocked. The color can be changed. The time when it resets from full to empty can be changed. + +When the battery is below a defined point, the watch's color can change to another chosen color to help the user notice that the battery is low. \ No newline at end of file diff --git a/apps/infoclk/app.js b/apps/infoclk/app.js new file mode 100644 index 000000000..6bc626018 --- /dev/null +++ b/apps/infoclk/app.js @@ -0,0 +1,405 @@ +const SETTINGS_FILE = "infoclk.json"; +const FONT = require('infoclk-font.js'); + +const storage = require("Storage"); +const locale = require("locale"); +const weather = require('weather'); + +let config = Object.assign({ + seconds: { + // Displaying the seconds can reduce battery life because the CPU must wake up more often to update the display. + // The seconds will be shown unless one of these conditions is enabled here, and currently true. + hideLocked: false, // Hide the seconds when the display is locked. + hideBattery: 20, // Hide the seconds when the battery is at or below a defined percentage. + hideTime: true, // Hide the seconds when between a certain period of time. Useful for when you are sleeping and don't need the seconds + hideStart: 2200, // The time when the seconds are hidden: first 2 digits are hours on a 24 hour clock, last 2 are minutes + hideEnd: 700, // The time when the seconds are shown again + hideAlways: false, // Always hide (never show) the seconds + }, + + date: { + // Settings related to the display of the date + mmdd: true, // If true, display the month first. If false, display the date first. + separator: '-', // The character that goes between the month and date + monthName: false, // If false, display the month as a number. If true, display the name. + monthFullName: false, // If displaying the name: If false, display an abbreviation. If true, display a full name. + dayFullName: false, // If false, display the day of the week's abbreviation. If true, display the full name. + }, + + bottomLocked: { + display: 'weather' // What to display in the bottom row when locked: + // 'weather': The current temperature and weather description + // 'steps': Step count + // 'health': Step count and bpm + // 'progress': Day progress bar + // false: Nothing + }, + + shortcuts: [ + //8 shortcuts, displayed in the bottom half of the screen (2 rows of 4 shortcuts) when unlocked + // false = no shortcut + // '#LAUNCHER' = open the launcher + // any other string = name of app to open + 'stlap', 'bgtimer', 'pomoplus', 'alarm', + 'rpnsci', 'calendar', 'torch', 'weather' + ], + + swipe: { + // 3 shortcuts to launch upon swiping: + // false = no shortcut + // '#LAUNCHER' = open the launcher + // any other string = name of app to open + up: 'messages', // Swipe up or swipe down, due to limitation of event handler + left: '#LAUNCHER', + right: '#LAUNCHER', + }, + + dayProgress: { + // A progress bar representing how far through the day you are + enabledLocked: true, // Whether this bar is enabled when the watch is locked + enabledUnlocked: false, // Whether the bar is enabled when the watch is unlocked + color: [0, 0, 1], // The color of the bar + start: 700, // The time of day that the bar starts filling + end: 2200, // The time of day that the bar becomes full + reset: 300 // The time of day when the progress bar resets from full to empty + }, + + lowBattColor: { + // The text can change color to indicate that the battery is low + level: 20, // The percentage where this happens + color: [1, 0, 0] // The color that the text changes to + } +}, storage.readJSON(SETTINGS_FILE)); + +// Return whether the given time (as a date object) is between start and end (as a number where the first 2 digits are hours on a 24 hour clock and the last 2 are minutes), with end time wrapping to next day if necessary +function timeInRange(start, time, end) { + + // Convert the given date object to a time number + let timeNumber = time.getHours() * 100 + time.getMinutes(); + + // Normalize to prevent the numbers from wrapping around at midnight + if (end <= start) { + end += 2400; + if (timeNumber < start) timeNumber += 2400; + } + + return start <= timeNumber && timeNumber <= end; +} + +// Return whether settings should be displayed based on the user's configuration +function shouldDisplaySeconds(now) { + return !( + (config.seconds.hideAlways) || + (config.seconds.hideLocked && Bangle.isLocked()) || + (E.getBattery() <= config.seconds.hideBattery) || + (config.seconds.hideTime && timeInRange(config.seconds.hideStart, now, config.seconds.hideEnd)) + ); +} + +// Determine the font size needed to fit a string of the given length widthin maxWidth number of pixels, clamped between minSize and maxSize +function getFontSize(length, maxWidth, minSize, maxSize) { + let size = Math.floor(maxWidth / length); //Number of pixels of width available to character + size *= (20 / 12); //Convert to height, assuming 20 pixels of height for every 12 of width + + // Clamp to within range + if (size < minSize) return minSize; + else if (size > maxSize) return maxSize; + else return Math.floor(size); +} + +// Get the current day of the week according to user settings +function getDayString(now) { + if (config.date.dayFullName) return ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][now.getDay()]; + else return ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][now.getDay()]; +} + +// Pad a number with zeros to be the given number of digits +function pad(number, digits) { + let result = '' + number; + while (result.length < digits) result = '0' + result; + return result; +} + +// Get the current date formatted according to the user settings +function getDateString(now) { + let month; + if (!config.date.monthName) month = pad(now.getMonth() + 1, 2); + else if (config.date.monthFullName) month = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][now.getMonth()]; + else month = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][now.getMonth()]; + + if (config.date.mmdd) return `${month}${config.date.separator}${pad(now.getDate(), 2)}`; + else return `${pad(now.getDate(), 2)}${config.date.separator}${month}`; +} + +// Get a floating point number from 0 to 1 representing how far between the user-defined start and end points we are +function getDayProgress(now) { + let start = config.dayProgress.start; + let current = now.getHours() * 100 + now.getMinutes(); + let end = config.dayProgress.end; + let reset = config.dayProgress.reset; + + // Normalize + if (end <= start) end += 2400; + if (current < start) current += 2400; + if (reset < start) reset += 2400; + + // Convert an hhmm number into a floating-point hours + function toDecimalHours(time) { + let hours = Math.floor(time / 100); + let minutes = time % 100; + + return hours + (minutes / 60); + } + + start = toDecimalHours(start); + current = toDecimalHours(current); + end = toDecimalHours(end); + reset = toDecimalHours(reset); + + let progress = (current - start) / (end - start); + + if (progress < 0 || progress > 1) { + if (current < reset) return 1; + else return 0; + } else { + return progress; + } +} + +// Get a Gadgetbridge weather string +function getWeatherString() { + let current = weather.get(); + if (current) return locale.temp(current.temp - 273.15) + ', ' + current.txt; + else return 'Weather unknown!'; +} + +// Get a second weather row showing humidity, wind speed, and wind direction +function getWeatherRow2() { + let current = weather.get(); + if (current) return `${current.hum}%, ${locale.speed(current.wind)} ${current.wrose}`; + else return 'Check Gadgetbridge'; +} + +// Get a step string +function getStepsString() { + return '' + Bangle.getHealthStatus('day').steps + ' steps'; +} + +// Get a health string including daily steps and recent bpm +function getHealthString() { + return `${Bangle.getHealthStatus('day').steps} steps ${Bangle.getHealthStatus('last').bpm} bpm`; +} + +// Set the next timeout to draw the screen +let drawTimeout; +function setNextDrawTimeout() { + if (drawTimeout) { + clearTimeout(drawTimeout); + drawTimeout = undefined; + } + + let time; + let now = new Date(); + if (shouldDisplaySeconds(now)) time = 1000 - (now.getTime() % 1000); + else time = 60000 - (now.getTime() % 60000); + + drawTimeout = setTimeout(draw, time); +} + + +const DIGIT_WIDTH = 40; // How much width is allocated for each digit, 37 pixels + 3 pixels of space (which will go off of the screen on the right edge) +const COLON_WIDTH = 19; // How much width is allocated for the colon, 16 pixels + 3 pixels of space +const HHMM_TOP = 27; // 24 pixels for widgets + 3 pixels of space +const DIGIT_HEIGHT = 64; // How tall the digits are + +const SECONDS_TOP = HHMM_TOP + DIGIT_HEIGHT + 3; // The top edge of the seconds, top of hours and minutes + digit height + space +const SECONDS_LEFT = 2 * DIGIT_WIDTH + COLON_WIDTH; // The left edge of the seconds: displayed after 2 digits and the colon +const DATE_LETTER_HEIGHT = DIGIT_HEIGHT / 2; // Each letter of the day of week and date will be half the height of the time digits + +const DATE_CENTER_X = SECONDS_LEFT / 2; // Day of week and date will be centered between left edge of screen and where seconds start +const DOW_CENTER_Y = SECONDS_TOP + (DATE_LETTER_HEIGHT / 2); // Day of week will be the top row +const DATE_CENTER_Y = DOW_CENTER_Y + DATE_LETTER_HEIGHT; // Date will be the bottom row +const DOW_DATE_CENTER_Y = SECONDS_TOP + (DIGIT_HEIGHT / 2); // When displaying both on one row, center it +const BOTTOM_CENTER_Y = ((SECONDS_TOP + DIGIT_HEIGHT + 3) + g.getHeight()) / 2; + +// Draw the clock +function draw() { + //Prepare to draw + g.reset() + .setFontAlign(0, 0); + + if (E.getBattery() <= config.lowBattColor.level) { + let color = config.lowBattColor.color; + g.setColor(color[0], color[1], color[2]); + } + now = new Date(); + + if (Bangle.isLocked()) { //When the watch is locked + g.clearRect(0, 24, g.getWidth(), g.getHeight()); + + //Draw the hours and minutes + let x = 0; + + for (let digit of locale.time(now, 1)) { //apparently this is how you get an hh:mm time string adjusting for the user's 12/24 hour preference + if (digit != ' ') g.drawImage(FONT[digit], x, HHMM_TOP); + if (digit == ':') x += COLON_WIDTH; + else x += DIGIT_WIDTH; + } + if (storage.readJSON('setting.json')['12hour']) g.drawImage(FONT[(now.getHours() < 12) ? 'am' : 'pm'], 0, HHMM_TOP); + + //Draw the seconds if necessary + if (shouldDisplaySeconds(now)) { + let tens = Math.floor(now.getSeconds() / 10); + let ones = now.getSeconds() % 10; + g.drawImage(FONT[tens], SECONDS_LEFT, SECONDS_TOP) + .drawImage(FONT[ones], SECONDS_LEFT + DIGIT_WIDTH, SECONDS_TOP); + + // Draw the day of week and date assuming the seconds are displayed + + g.setFont('Vector', getFontSize(getDayString(now).length, SECONDS_LEFT, 6, DATE_LETTER_HEIGHT)) + .drawString(getDayString(now), DATE_CENTER_X, DOW_CENTER_Y) + .setFont('Vector', getFontSize(getDateString(now).length, SECONDS_LEFT, 6, DATE_LETTER_HEIGHT)) + .drawString(getDateString(now), DATE_CENTER_X, DATE_CENTER_Y); + + } else { + //Draw the day of week and date without the seconds + + let string = getDayString(now) + ' ' + getDateString(now); + g.setFont('Vector', getFontSize(string.length, g.getWidth(), 6, DATE_LETTER_HEIGHT)) + .drawString(string, g.getWidth() / 2, DOW_DATE_CENTER_Y); + } + + // Draw the bottom area + if (config.bottomLocked.display == 'progress') { + let color = config.dayProgress.color; + g.setColor(color[0], color[1], color[2]) + .fillRect(0, SECONDS_TOP + DIGIT_HEIGHT + 3, g.getWidth() * getDayProgress(now), g.getHeight()); + } else { + let bottomString; + + if (config.bottomLocked.display == 'weather') bottomString = getWeatherString(); + else if (config.bottomLocked.display == 'steps') bottomString = getStepsString(); + else if (config.bottomLocked.display == 'health') bottomString = getHealthString(); + else bottomString = ' '; + + g.setFont('Vector', getFontSize(bottomString.length, 176, 6, g.getHeight() - (SECONDS_TOP + DIGIT_HEIGHT + 3))) + .drawString(bottomString, g.getWidth() / 2, BOTTOM_CENTER_Y); + } + + // Draw the day progress bar between the rows if necessary + if (config.dayProgress.enabledLocked && config.bottomLocked.display != 'progress') { + let color = config.dayProgress.color; + g.setColor(color[0], color[1], color[2]) + .fillRect(0, HHMM_TOP + DIGIT_HEIGHT, g.getWidth() * getDayProgress(now), SECONDS_TOP); + } + } else { + + //If the watch is unlocked + g.clearRect(0, 24, g.getWidth(), g.getHeight() / 2); + rows = [ + `${getDayString(now)} ${getDateString(now)} ${locale.time(now, 1)}`, + getHealthString(), + getWeatherString(), + getWeatherRow2() + ]; + if (shouldDisplaySeconds(now)) rows[0] += ':' + pad(now.getSeconds(), 2); + if (storage.readJSON('setting.json')['12hour']) rows[0] += ((now.getHours() < 12) ? ' AM' : ' PM'); + + let maxHeight = ((g.getHeight() / 2) - HHMM_TOP) / (config.dayProgress.enabledUnlocked ? (rows.length + 1) : rows.length); + + let y = HHMM_TOP + maxHeight / 2; + for (let row of rows) { + let size = getFontSize(row.length, g.getWidth(), 6, maxHeight); + g.setFont('Vector', size) + .drawString(row, g.getWidth() / 2, y); + y += maxHeight; + } + + if (config.dayProgress.enabledUnlocked) { + let color = config.dayProgress.color; + g.setColor(color[0], color[1], color[2]) + .fillRect(0, y - maxHeight / 2, 176 * getDayProgress(now), y + maxHeight / 2); + } + } + + setNextDrawTimeout(); +} + +// Draw the icons. This is done separately from the main draw routine to avoid having to scale and draw a bunch of images repeatedly. +function drawIcons() { + g.reset().clearRect(0, 24, g.getWidth(), g.getHeight()); + for (let i = 0; i < 8; i++) { + let x = [0, 44, 88, 132, 0, 44, 88, 132][i]; + let y = [88, 88, 88, 88, 132, 132, 132, 132][i]; + let appId = config.shortcuts[i]; + let appInfo = storage.readJSON(appId + '.info', 1); + if (!appInfo) continue; + icon = storage.read(appInfo.icon); + g.drawImage(icon, x, y, { + scale: 0.916666666667 + }); + } +} + +weather.on("update", draw); +Bangle.on("step", draw); +Bangle.on('lock', locked => { + //If the watch is unlocked, draw the icons + if (!locked) drawIcons(); + draw(); +}); + +// Show launcher when middle button pressed +Bangle.setUI("clock"); +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +// Launch an app given the current ID. Handles special cases: +// false: Do nothing +// '#LAUNCHER': Open the launcher +// nonexistent app: Do nothing +function launch(appId) { + if (appId == false) return; + else if (appId == '#LAUNCHER') { + Bangle.buzz(); + Bangle.showLauncher(); + } else { + let appInfo = storage.readJSON(appId + '.info', 1); + if (appInfo) { + Bangle.buzz(); + load(appInfo.src); + } + } +} + +//Set up touch to launch the selected app +Bangle.on('touch', function (button, xy) { + let x = Math.floor(xy.x / 44); + if (x < 0) x = 0; + else if (x > 3) x = 3; + + let y = Math.floor(xy.y / 44); + if (y < 0) y = -1; + else if (y > 3) y = 1; + else y -= 2; + + if (y < 0) { + Bangle.buzz(); + Bangle.showLauncher(); + } else { + let i = 4 * y + x; + launch(config.shortcuts[i]); + } +}); + +//Set up swipe handler +Bangle.on('swipe', function (direction) { + if (direction == -1) launch(config.swipe.left); + else if (direction == 0) launch(config.swipe.up); + else launch(config.swipe.right); +}); + +if (!Bangle.isLocked()) drawIcons(); + +draw(); \ No newline at end of file diff --git a/apps/infoclk/font.js b/apps/infoclk/font.js new file mode 100644 index 000000000..6063958e7 --- /dev/null +++ b/apps/infoclk/font.js @@ -0,0 +1,23 @@ +const heatshrink = require("heatshrink") + +function decompress(string) { + return heatshrink.decompress(atob(string)) +} + +exports = { + '0': decompress("ktAwIEB////EAj4EB+EDAYP/8E/AgWDAYX+CIX/+IDC//PBoYIDAAvwgEHAgOAgAnB/kAgIvCgEPAgJCBv5CCHwXAI4X+KAYk/En4kmAA4qBAAP7BAePAYX4BofBAYX8F4Q+BEwRHBIQI5BA"), + '1': decompress("ktAwIGDj/4AgX/4ADBg/+BAU/+ADBgP/wAEBh/8BoV/8ADBgf/En4k/En4k/EgQ="), + '2': decompress("ktAwMA/4AB/EHAgXwn4EC8IDC/+PAYX+v4EC+YND74NDBAYAE4A0Bg/+HIU/+ADBgP/wAEBh/8BoV/8ADBgf/BAUf/AECElQdBPA2HAYX8OYfHBAYRD8Z3Dj6TG/kPPYZm4EiwAHO4f7BAfPfI/xBoaTEPAfgQwY"), + '3': decompress("ktAwMA/4AB/EHAgXwn4EC8IDC/+PAYX+v4EC+YND74NDBAYAE4A0Bg/+HIU/+ADBgP/wAEBh/8BoV/8ADBgf/BAUf/AECElJWIAEpu/EhpgS34DC/IID54DC/l/AgXDAYX4j57DA"), + '4': decompress("ktAwMA//AgEf//+BYP///wgEHAgOAgE///8gEBBAPggEPAgIWBv///EAgYIBEn4kXABf9AgfnAgY4BAAP4BAfDAYX+EwfwIQRRCJIJRBJIRRBJIQICj5RBJIRRBJIJRCNwJRBNwQk/Ei4A=="), + '5': decompress("ktAwIEB/4AB/EfAgXDAYX+n4EC+YDC/+fAYX9BAfvAgYAJ+AwBgP/wAEBh/8H4V/8ADBgf/BAUf/AEC//AAYMH/wICn4kpPYUPAgXgv4EC4JfDg4DC/iFD8ANDwaTDCQfwEoZ2/EhrXNAAm/AYX5BAfPQoaTD4ahDj57DA=="), + '6': decompress("ktAwIEB/4AB/EfAgXDAYX+n4EC+YDC/+fAYX9BAfvAgYAJ+AwBgP/wAEBh/8H4V/8ADBgf/BAUf/AEC//AAYMH/wICn4kpPYUPAgXgv6AG/6JD/gID84ED358NJIIsCKIQ0BKIRJCFgJJCSYcHAgJuBXYJuBKIQkpAA58D/YIDx6PDBofBQoYvCHwImCI4KUCwA="), + '7': decompress("ktAwMA/4AB/EHAgXwn4EC8IDC/+PAYX+v4EC+YND74NDBAYAE4A0Bg/+HIU/+ADBgP/wAEBh/8BoV/8ADBgf/BAUf/AECEn4k/En4kVA"), + '8': decompress("ktAwIEB////EAj4EB+EDAYP/8E/AgWDAYX+CIX/+IDC//PBoYIDAAvwgEHAgOAgAnB/kAgIvCgEPAgJCBv5CCHwXAI4X+KAYkpAFpu/EhwAHFQIAB/YIDx4DC/AND4IDC/ieD4AmCI4JCBHIIA=="), + '9': decompress("ktAwIEB////EAj4EB+EDAYP/8E/AgWDAYX+CIX/+IDC//PBoYIDAAvwgEHAgOAgAnB/kAgIvCgEPAgJCBv5CCHwXAI4X+KAYkpABf9AgfnAgaFD/AID4Z8DEwfwIQRRCJIJRBJIRRBJIQICj5RBJIRRBJIJRCNwJRBNwQkoPhoAE34DC/L0H/iwBQAv4WAJ7CA=="), + + ':': decompress("iFAwITQg/gj/4n/8v/+AIP/ABQPDCoIZBDoJTfH94A=="), + + 'am': decompress("jFAwIEBngCEvwCH/4CFwEBAQkD//AgfnAQcH4fgAQsPwPwAQf/+Ef//4AQn8n0AvgCCHQN+vkAnwCC/EAj4CF+EAh4CCNIoLFC4v8gE/AQv+gF/AQpwB/4CDwICG+/D94CD8/v+fn54CC+P/x4CF+H/IgICFvwCEngCD"), + 'pm': decompress("jFAwMAn///l///+/4AE+EAh4CaEYoABFgX8BwMAAUwAFIIv4gEfAQX8OYICF/0Av4CF/8AKQICCwICG+/D94CD8/v+fn54CC+P/x4CF+H/IgICFvwCEngCDA") +} \ No newline at end of file diff --git a/apps/infoclk/font/am.png b/apps/infoclk/font/am.png new file mode 100644 index 0000000000000000000000000000000000000000..a76ad25fc8bd5b987689eda614a1bfb519259243 GIT binary patch literal 360 zcmV-u0hj)XP)fJj5NVp zUZW%r0XQG8upV*+rNxE7=eg4Y&JKH3P?Fr-8o0L`pn7UhLqTzOB=2izQx`x>a%HlU zg7pAu5Kw*T=164G;{X*=)AQD7CA^D8RW}#6qSvegIWYr!!j6nAqBH+AfD#pO8etZ# z0dQ2%VNF@o1;8M3)N~Zg2XGr88WyZirZZ_g4!GumjhdE%bXe_0{5=4qBI?%g8lXP< zvXFM#djXD3^dhM&S_8mT$iE^Si@E?J2pXL2N>=wT3-AMt$$=hV8R&5U0000FtYi*xWC%KNFBJ~#n2-^57*E11a! zmI=JzNm4=(y?sQ{BLG1`4tg@9iEJf(z+L5yVrgYB$yQ8KabY>TT^_c6v#p!Ui87*$ za=7Zo2^)&l7qK6Rlw&_A+L5py>?c52&gOx#tn6--(n1D*@uSQ9TmMhz7ny<}HUB<5 SKmY&$07*qoM6N<$f&c&qqgFit literal 0 HcmV?d00001 diff --git a/apps/infoclk/font/digit0.png b/apps/infoclk/font/digit0.png new file mode 100644 index 0000000000000000000000000000000000000000..5470154ee601c8829b3f254c35a8ed21ef90245f GIT binary patch literal 290 zcmV+-0p0$IP)c zQ7Z%$fv1+MsFi{$VXj4apmfqIq}++}Bq-5}q<$@GxC)DFx&**N3Q-c$>_2gqx?$2- zOrM(Rkb;yUCCNS&7Nj6`B|w!RWdv1%x*tIbQsVC%MV@LENI^=iTOb9gh5$t#MV^ur zY%?sLicfNklvH>MPp$NnVeGk3i_zysGW7O%2$|0NVw2Vn!^h5q2G<{907*qoM6N<$f)`wN#sB~S literal 0 HcmV?d00001 diff --git a/apps/infoclk/font/digit1.png b/apps/infoclk/font/digit1.png new file mode 100644 index 0000000000000000000000000000000000000000..26a35fd1be9685e70fba18845d231e5087436a99 GIT binary patch literal 183 zcmeAS@N?(olHy`uVBq!ia0vp^szB_(!3HGfF5mYGNY#0|IEG|6zrD1PmqCGt#cCllQ1FmvHB)s96`^Y4Bm2~FN2i??W?-cZ2{06micQ(n!twLzqq1zurlY7_^s%tLA)M4(T zmSpNOrYShdYZ|Fm!bDRo@hjJ~`zS0)Ns1DnIx{6H zN`UHcrjU@1Iztz`9hMX+ujM0@&I1KAMQE8RLg{vTMnCwdL;1BCwHY1AnVF)nBqb?I zfa=VYq$mNZGgH$^A*6KF89Mjqlwu;OxId$X!ZiIvpp(#m`T$(9bRFaYu zsi;GP+K-tsQ)cQyz|jTu4u?G2J0vA3_~+z%?lf~`?*7~yG1Xt&_m${?nxaiwQj$uPr`1PcNlH?b x0M(f(Nl^k+XQm`Y2~eGxk`yICb!O^SQadKJTLI?SZzBKz002ovPDHLkV1lOcXY>F7 literal 0 HcmV?d00001 diff --git a/apps/infoclk/font/digit5.png b/apps/infoclk/font/digit5.png new file mode 100644 index 0000000000000000000000000000000000000000..5647ad00a4203ac500bbc91a35a969826f5674e4 GIT binary patch literal 302 zcmV+}0nz@6P)Nkl`;@!S-AC%m-A63B`=}+G zddgJfz9c*RLPWL%vQRYB1=|hPozx2{{nSKFMDmw4wXyx=k%!8V60h+S=TmiIZnH-I z;=T??pdxKO%c2J~6zy)CvZ-0iRoC5pRF+NI6g5C|t|^5)ttI0m}&-?-8Ch5k~bXh4s1|BAkDn&#{d8T07*qoM6N<$g7N~2 AhyVZp literal 0 HcmV?d00001 diff --git a/apps/infoclk/font/digit6.png b/apps/infoclk/font/digit6.png new file mode 100644 index 0000000000000000000000000000000000000000..56c44688139cda32620387169e5deb5952a6ef6f GIT binary patch literal 309 zcmV-50m}Y~P)*_2HMO3~FvW!aQXwFZ1jKovogW<^|N?^`h+8l&cklr2T5 za__63f~~?M50xQz+ByWO{8n<}n04tltPNlC?s~^la6=(KE3i=@8qlkn00000NkvXX Hu0mjfeT0Q( literal 0 HcmV?d00001 diff --git a/apps/infoclk/font/digit7.png b/apps/infoclk/font/digit7.png new file mode 100644 index 0000000000000000000000000000000000000000..1fb6a64237347be6e572ef6b3bfe9e56dfbe5d9f GIT binary patch literal 227 zcmeAS@N?(olHy`uVBq!ia0vp^szB_(!3HGfF5mYGNUid8aSX|DetX4{>wtm)%fY+< z?X4UY=egYSj#*fI)}ifGhT9S0|Mok7rBqigx^g`;>Rrjo%$-_GqjoL~TX{tzO|#;} z=2;>CTSdLU9-Y5u`LgJA0AC4(2Ql0u6QU>ezLM@*1^<-!raS<}F_u*7E z4Av8xLN9Dbp_L(p-z-slfTjYEX&P-ea2~S(ryj^Ca=Sn#%DQ3@@%8EX00000NkvXX Hu0mjf3Gst1 literal 0 HcmV?d00001 diff --git a/apps/infoclk/font/digit9.png b/apps/infoclk/font/digit9.png new file mode 100644 index 0000000000000000000000000000000000000000..990a3a43bbb16093a9aa37e999b57a60e04fa01a GIT binary patch literal 319 zcmV-F0l@x=P)9rRKuR68M;BUa9{j4h>G zm(m0(_fu6@M&IN$rwFoiJYH)A3Qc%02>n4r(Mj5-YzlTBUie*8t|`~lf&m)pwa=!g z0UC#E3I)suX+_e~LlDg_)357zhHk;Au>pp-JWvaUs{{RbVQ4q_& R&KCdx002ovPDHLkV1hy|g)IO8 literal 0 HcmV?d00001 diff --git a/apps/infoclk/font/pm.png b/apps/infoclk/font/pm.png new file mode 100644 index 0000000000000000000000000000000000000000..a3db97eb8c51fc817b78d347b41b5ce7d4851d3e GIT binary patch literal 327 zcmV-N0l5B&P)kh*p2!-|iA9_ohbwdjruwL4Q{aBi4{mQ`{(42n17kTdSn72jtzm!t%#g7ln8(`Gp zJ7fvqkgYWjg(6%80SJlU<_d|fO9WT&OjzPYo)1KGhuZbG;MDcts@WA$jd0Tdpp8?G zM-HG~AyG&K6@U}EIwwb)0_a^2*7rs9Xa$p4O*oyFq^_bhH)cRf6zo|~>x;Zm+z;T9 zNjwUp*3l}{eE}Ak)SCh%(G-9Nf%hDi2%ZP9`V%M5>0PNWl3u3f*&RT0Atl!wfppEL zUBR(qTI;CEWFAAkDct9uq)^Xt)#T>`q-4|WT3fnHqW=JBQE(N{EzuMJ2a)P^Qv}U` ZH{YFl6>+g)wEzGB07*qoM6N<$f&h;Vja~o% literal 0 HcmV?d00001 diff --git a/apps/infoclk/icon.js b/apps/infoclk/icon.js new file mode 100644 index 000000000..2db8a7a9a --- /dev/null +++ b/apps/infoclk/icon.js @@ -0,0 +1,2 @@ +//TODO replace app icon with my own +require("heatshrink").decompress(atob("mEwgX/AH4A/AAf+14BBAoPq/Wq1QFB+EP+kLAoNA+CdB3//yEP6ALB/sABYf8gEMgALB6ALJqoLB+tVgH//kQhkQhUABYImCIwPwh3whcA94UCgJHD+AXB/4LCcQQLCKYQLB+EDBZQFCBY/Qh4LJ4ALLl4LFioLCgE/KZMAv4XFBYimBC4/+BYw7DRwQLIV4ILWTQQLDOIUA/ALDAC+t1uv/263/6/Pq/YLC3vv//vM4Oq33rBYP6/u//2/C4Pr1YXC12vBwO+BYO69XmJDQA/ACIA==")) diff --git a/apps/infoclk/icon.png b/apps/infoclk/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a38093c5f3b6f88dbc9b75017422dbe237d4407f GIT binary patch literal 1989 zcmV;$2RitPP)jLx_$n|!#a_+a7!4?Zj*KoBI+mq8Z8#{*+o z7DHwNZgKLU(NGK;MJHm2(2Z3wlN9^G$Dl3PLZR*L$JxWF_g-#q5pXO%?4OgH|2gM( z&iUPY&i~`w2to*6Cz0Salm7|*Pv});Rk#kH&o?nKVKf?JV`CKxgR&1SYr2-&`UyG$k%PDI4SU@#m$e3%a_DJdBl84(40z238D&kClk zs;Y82oqX8o)29U(i^UQ;n+PGB&6b*)8u|?i3JT`t=0fr3&YhD;M7F-UxtYZ<46||L z#$^(^di83!ed+D(C4@{&Ojs-yi^VcGH|KCTl9H16n23l7R(HGIbWWX4$8TSNkjR^L zcXzY8Ua#-%?PaT@qoV@@0~H&dOV(ykrCQkT3X65OnG@Zi=UX7pvt31 zj}{pcL)2{nR~LU?!AoakWJE?r@;{iv;h@Tm8#ky@Q&Y1{D-)+L zk?;ux0)h4G*YjJ(#>Q^nzRiCh09LE@!i5U}3JVKgYOOCJ6uR+Sw{CU2-NC`D<_&Lc zZ7nJ)ve|63T3A>ZA0H23aBz^e?A^OJbi$<(>ged0o}Lzbr0D2qQLxA3VcF#5df&c%%k%pC z_wR3NYGVEE(W6Hhh8Y?fqAfC+OyD3EODH`({lS9=J9q8`AeBm6T3YzMGcz-7ZEYHj zMx)V~&1Q$gG4w*>jhws#}m#f8yXryC+C~U z`1tsuqP^K{Rw|XD3shHEi{?XpeSM+eoSYo1)w(dD#ik#GkY~@Hm6eqVUYB7Q5=Ndr zeOgynw`b2D8Znxin?>0WLatxGUQtm|QBiU7#}wE{v` zE79qQ-%ki34hQ+;590L_Ldfha>Fp)d!~y~G@F9PBpO089!Qyrkhl5){BH^9@$<8K( zknwSGHUObsMZ!iMoIj7rNmN(E>qSis+-{VX!tckAKO!Om1qJYW@$I*me+7H^5OR62 z3=ZN&Qctf5g8}2?{1^qN6CZvUtlqoFPd{WbR8}H06H+N04!rjsKKcl1 zHT-^*mm?zsDJcj9aOMowuALuH=N;9*{^ImQhp>7z6pDG^{(i2SkbpPdKwMlnD;pTV zci*9=hFgSsgt0MHSEIZfVy=i!h!F4{kf=Wi^-z~Cfu=;}wcszLg7?YD27=Y7B$L-n$w>wz2ZCjda2n2$gD3L&|#yjuu z2}MPrp#d%zrl%1bi`-l|95{0Zk&&pa4elc$u-j2t3A-JBKOHBPB04%)Buo62QdtSL z8t=akwHjq*n3-7tKg75Bwl+ctsi@#u^m@|L64uIo{WZ*0`actu3LkvHRe$=4-LlzP zG&h4@(OoVyHR0!>Q z7SEqkLVx}VyB!`6&AgGFjjSwOzRV5%{dYK>@c97X&K-RDB~&Whx&>fx5P5mX%|&i5 zES9AaijKycZ{po|gH^j7J|8vvUAr(f#a_qZa-p>qnVHb*(cO)YKgK7YfW2`_r7##U zGXuN*KZ*8JQ)q0&kt0Y?hs%Wn2Ovn)Km8PaeXKu8NC11$U9)D%%lmw+13^*}qN6FH z-+sfTOGr$_fdjDHVKCt4O^lA>^Up#50d{oY$`u$4$j*jDf}1ztbmFV80BqTUEnC3* z|HA1lEy&D-(a5<(Lh$z69KdWwOblM!|B#xBHEXEZd%eW%CT=(JdO4k+urdq>AVk>9 z6Q`5N<>FSIpHBh-Vlss_`<9lKNk2L}#ngwjPIdq7ye|T3ar}q0{vjtPwx88zODg-bLj7E4oP%5!@EeCk*lKg)F X^{k9p7{Urq00000NkvXXu0mjf6Vk;2 literal 0 HcmV?d00001 diff --git a/apps/infoclk/metadata.json b/apps/infoclk/metadata.json new file mode 100644 index 000000000..bb6dea3a4 --- /dev/null +++ b/apps/infoclk/metadata.json @@ -0,0 +1,38 @@ +{ + "id": "infoclk", + "name": "Informational clock", + "version": "0.08", + "description": "A configurable clock with extra info and shortcuts when unlocked, but large time when locked", + "readme": "README.md", + "icon": "icon.png", + "type": "clock", + "tags": "clock", + "supports": [ + "BANGLEJS2" + ], + "allow_emulator": true, + "storage": [ + { + "name": "infoclk.app.js", + "url": "app.js" + }, + { + "name": "infoclk.settings.js", + "url": "settings.js" + }, + { + "name": "infoclk-font.js", + "url": "font.js" + }, + { + "name": "infoclk.img", + "url": "icon.js", + "evaluate": true + } + ], + "data": [ + { + "name": "infoclk.json" + } + ] +} \ No newline at end of file diff --git a/apps/infoclk/settings.js b/apps/infoclk/settings.js new file mode 100644 index 000000000..d12225f99 --- /dev/null +++ b/apps/infoclk/settings.js @@ -0,0 +1,571 @@ +(function (back) { + const SETTINGS_FILE = "infoclk.json"; + const storage = require('Storage'); + + let config = Object.assign({ + seconds: { + // Displaying the seconds can reduce battery life because the CPU must wake up more often to update the display. + // The seconds will be shown unless one of these conditions is enabled here, and currently true. + hideLocked: false, // Hide the seconds when the display is locked. + hideBattery: 20, // Hide the seconds when the battery is at or below a defined percentage. + hideTime: true, // Hide the seconds when between a certain period of time. Useful for when you are sleeping and don't need the seconds + hideStart: 2200, // The time when the seconds are hidden: first 2 digits are hours on a 24 hour clock, last 2 are minutes + hideEnd: 700, // The time when the seconds are shown again + hideAlways: false, // Always hide (never show) the seconds + }, + + date: { + // Settings related to the display of the date + mmdd: true, // If true, display the month first. If false, display the date first. + separator: '-', // The character that goes between the month and date + monthName: false, // If false, display the month as a number. If true, display the name. + monthFullName: false, // If displaying the name: If false, display an abbreviation. If true, display a full name. + dayFullName: false, // If false, display the day of the week's abbreviation. If true, display the full name. + }, + + bottomLocked: { + display: 'weather' // What to display in the bottom row when locked: + // 'weather': The current temperature and weather description + // 'steps': Step count + // 'health': Step count and bpm + // 'progress': Day progress bar + // false: Nothing + }, + + shortcuts: [ + //8 shortcuts, displayed in the bottom half of the screen (2 rows of 4 shortcuts) when unlocked + // false = no shortcut + // '#LAUNCHER' = open the launcher + // any other string = name of app to open + 'stlap', 'bgtimer', 'pomoplus', 'alarm', + 'rpnsci', 'calendar', 'torch', 'weather' + ], + + swipe: { + // 3 shortcuts to launch upon swiping: + // false = no shortcut + // '#LAUNCHER' = open the launcher + // any other string = name of app to open + up: 'messages', // Swipe up or swipe down, due to limitation of event handler + left: '#LAUNCHER', + right: '#LAUNCHER', + }, + + dayProgress: { + // A progress bar representing how far through the day you are + enabledLocked: true, // Whether this bar is enabled when the watch is locked + enabledUnlocked: false, // Whether the bar is enabled when the watch is unlocked + color: [0, 0, 1], // The color of the bar + start: 700, // The time of day that the bar starts filling + end: 2200, // The time of day that the bar becomes full + reset: 300 // The time of day when the progress bar resets from full to empty + }, + + lowBattColor: { + // The text can change color to indicate that the battery is low + level: 20, // The percentage where this happens + color: [1, 0, 0] // The color that the text changes to + } + }, storage.readJSON(SETTINGS_FILE)); + + function saveSettings() { + storage.writeJSON(SETTINGS_FILE, config); + } + + function hourToString(hour) { + if (storage.readJSON('setting.json')['12hour']) { + if (hour == 0) return '12 AM'; + else if (hour < 12) return `${hour} AM`; + else if (hour == 12) return '12 PM'; + else return `${hour - 12} PM`; + } else return '' + hour; + } + + // The menu for configuring when the seconds are shown + function showSecondsMenu() { + E.showMenu({ + '': { + 'title': 'Seconds display', + 'back': showMainMenu + }, + 'Show seconds': { + value: !config.seconds.hideAlways, + onchange: value => { + config.seconds.hideAlways = !value; + saveSettings(); + } + }, + '...unless locked': { + value: config.seconds.hideLocked, + onchange: value => { + config.seconds.hideLocked = value; + saveSettings(); + } + }, + '...unless battery below': { + value: config.seconds.hideBattery, + min: 0, + max: 100, + format: value => `${value}%`, + onchange: value => { + config.seconds.hideBattery = value; + saveSettings(); + } + }, + '...unless between these 2 times...': () => { + E.showMenu({ + '': { + 'title': 'Hide seconds between', + 'back': showSecondsMenu + }, + 'Enabled': { + value: config.seconds.hideTime, + onchange: value => { + config.seconds.hideTime = value; + saveSettings(); + } + }, + 'Start hour': { + value: Math.floor(config.seconds.hideStart / 100), + format: hourToString, + min: 0, + max: 23, + wrap: true, + onchange: hour => { + minute = config.seconds.hideStart % 100; + config.seconds.hideStart = (100 * hour) + minute; + saveSettings(); + } + }, + 'Start minute': { + value: config.seconds.hideStart % 100, + min: 0, + max: 59, + wrap: true, + onchange: minute => { + hour = Math.floor(config.seconds.hideStart / 100); + config.seconds.hideStart = (100 * hour) + minute; + saveSettings(); + } + }, + 'End hour': { + value: Math.floor(config.seconds.hideEnd / 100), + format: hourToString, + min: 0, + max: 23, + wrap: true, + onchange: hour => { + minute = config.seconds.hideEnd % 100; + config.seconds.hideEnd = (100 * hour) + minute; + saveSettings(); + } + }, + 'End minute': { + value: config.seconds.hideEnd % 100, + min: 0, + max: 59, + wrap: true, + onchange: minute => { + hour = Math.floor(config.seconds.hideEnd / 100); + config.seconds.hideEnd = (100 * hour) + minute; + saveSettings(); + } + } + }); + } + }); + } + + // Available month/date separators + const SEPARATORS = [ + { name: 'Slash', char: '/' }, + { name: 'Dash', char: '-' }, + { name: 'Space', char: ' ' }, + { name: 'Comma', char: ',' }, + { name: 'None', char: '' } + ]; + + // Available bottom row display options + const BOTTOM_ROW_OPTIONS = [ + { name: 'Weather', val: 'weather' }, + { name: 'Step count', val: 'steps' }, + { name: 'Steps + BPM', val: 'health' }, + { name: 'Day progresss bar', val: 'progress' }, + { name: 'Nothing', val: false } + ]; + + // The menu for configuring which apps have shortcut icons + function showShortcutMenu() { + //Builds the shortcut options + let shortcutOptions = [ + { name: 'Nothing', val: false }, + { name: 'Launcher', val: '#LAUNCHER' }, + ]; + + let infoFiles = storage.list(/\.info$/).sort((a, b) => { + if (a.name < b.name) return -1; + else if (a.name > b.name) return 1; + else return 0; + }); + for (let infoFile of infoFiles) { + let appInfo = storage.readJSON(infoFile); + if (appInfo.src) shortcutOptions.push({ + name: appInfo.name, + val: appInfo.id + }); + } + + E.showMenu({ + '': { + 'title': 'Shortcuts', + 'back': showMainMenu + }, + 'Top first': { + value: shortcutOptions.map(item => item.val).indexOf(config.shortcuts[0]), + format: value => shortcutOptions[value].name, + min: 0, + max: shortcutOptions.length - 1, + wrap: false, + onchange: value => { + config.shortcuts[0] = shortcutOptions[value].val; + saveSettings(); + } + }, + 'Top second': { + value: shortcutOptions.map(item => item.val).indexOf(config.shortcuts[1]), + format: value => shortcutOptions[value].name, + min: 0, + max: shortcutOptions.length - 1, + wrap: false, + onchange: value => { + config.shortcuts[1] = shortcutOptions[value].val; + saveSettings(); + } + }, + 'Top third': { + value: shortcutOptions.map(item => item.val).indexOf(config.shortcuts[2]), + format: value => shortcutOptions[value].name, + min: 0, + max: shortcutOptions.length - 1, + wrap: false, + onchange: value => { + config.shortcuts[2] = shortcutOptions[value].val; + saveSettings(); + } + }, + 'Top fourth': { + value: shortcutOptions.map(item => item.val).indexOf(config.shortcuts[3]), + format: value => shortcutOptions[value].name, + min: 0, + max: shortcutOptions.length - 1, + wrap: false, + onchange: value => { + config.shortcuts[3] = shortcutOptions[value].val; + saveSettings(); + } + }, + 'Bottom first': { + value: shortcutOptions.map(item => item.val).indexOf(config.shortcuts[4]), + format: value => shortcutOptions[value].name, + min: 0, + max: shortcutOptions.length - 1, + wrap: false, + onchange: value => { + config.shortcuts[4] = shortcutOptions[value].val; + saveSettings(); + } + }, + 'Bottom second': { + value: shortcutOptions.map(item => item.val).indexOf(config.shortcuts[5]), + format: value => shortcutOptions[value].name, + min: 0, + max: shortcutOptions.length - 1, + wrap: false, + onchange: value => { + config.shortcuts[5] = shortcutOptions[value].val; + saveSettings(); + } + }, + 'Bottom third': { + value: shortcutOptions.map(item => item.val).indexOf(config.shortcuts[6]), + format: value => shortcutOptions[value].name, + min: 0, + max: shortcutOptions.length - 1, + wrap: false, + onchange: value => { + config.shortcuts[6] = shortcutOptions[value].val; + saveSettings(); + } + }, + 'Bottom fourth': { + value: shortcutOptions.map(item => item.val).indexOf(config.shortcuts[7]), + format: value => shortcutOptions[value].name, + min: 0, + max: shortcutOptions.length - 1, + wrap: false, + onchange: value => { + config.shortcuts[7] = shortcutOptions[value].val; + saveSettings(); + } + }, + 'Swipe up': { + value: shortcutOptions.map(item => item.val).indexOf(config.swipe.up), + format: value => shortcutOptions[value].name, + min: 0, + max: shortcutOptions.length - 1, + wrap: false, + onchange: value => { + config.swipe.up = shortcutOptions[value].val; + saveSettings(); + } + }, + 'Swipe left': { + value: shortcutOptions.map(item => item.val).indexOf(config.swipe.left), + format: value => shortcutOptions[value].name, + min: 0, + max: shortcutOptions.length - 1, + wrap: false, + onchange: value => { + config.swipe.left = shortcutOptions[value].val; + saveSettings(); + } + }, + 'Swipe right': { + value: shortcutOptions.map(item => item.val).indexOf(config.swipe.right), + format: value => shortcutOptions[value].name, + min: 0, + max: shortcutOptions.length - 1, + wrap: false, + onchange: value => { + config.swipe.right = shortcutOptions[value].val; + saveSettings(); + } + }, + }); + } + + const COLOR_OPTIONS = [ + { name: 'Black', val: [0, 0, 0] }, + { name: 'Blue', val: [0, 0, 1] }, + { name: 'Green', val: [0, 1, 0] }, + { name: 'Cyan', val: [0, 1, 1] }, + { name: 'Red', val: [1, 0, 0] }, + { name: 'Magenta', val: [1, 0, 1] }, + { name: 'Yellow', val: [1, 1, 0] }, + { name: 'White', val: [1, 1, 1] } + ]; + + // Workaround for being unable to use == on arrays: convert them into strings + function colorString(color) { + return `${color[0]} ${color[1]} ${color[2]}`; + } + + //Shows the top level menu + function showMainMenu() { + E.showMenu({ + '': { + 'title': 'Informational Clock', + 'back': back + }, + 'Seconds display': showSecondsMenu, + 'Day of week format': { + value: config.date.dayFullName, + format: value => value ? 'Full name' : 'Abbreviation', + onchange: value => { + config.date.dayFullName = value; + saveSettings(); + } + }, + 'Date format': () => { + E.showMenu({ + '': { + 'title': 'Date format', + 'back': showMainMenu, + }, + 'Order': { + value: config.date.mmdd, + format: value => value ? 'Month first' : 'Date first', + onchange: value => { + config.date.mmdd = value; + saveSettings(); + } + }, + 'Separator': { + value: SEPARATORS.map(item => item.char).indexOf(config.date.separator), + format: value => SEPARATORS[value].name, + min: 0, + max: SEPARATORS.length - 1, + wrap: true, + onchange: value => { + config.date.separator = SEPARATORS[value].char; + saveSettings(); + } + }, + 'Month format': { + // 0 = number only + // 1 = abbreviation + // 2 = full name + value: config.date.monthName ? (config.date.monthFullName ? 2 : 1) : 0, + format: value => ['Number', 'Abbreviation', 'Full name'][value], + min: 0, + max: 2, + wrap: true, + onchange: value => { + if (value == 0) config.date.monthName = false; + else { + config.date.monthName = true; + config.date.monthFullName = (value == 2); + } + saveSettings(); + } + } + }); + }, + 'Bottom row': { + value: BOTTOM_ROW_OPTIONS.map(item => item.val).indexOf(config.bottomLocked.display), + format: value => BOTTOM_ROW_OPTIONS[value].name, + min: 0, + max: BOTTOM_ROW_OPTIONS.length - 1, + wrap: true, + onchange: value => { + config.bottomLocked.display = BOTTOM_ROW_OPTIONS[value].val; + saveSettings(); + } + }, + 'Shortcuts': showShortcutMenu, + 'Day progress': () => { + E.showMenu({ + '': { + 'title': 'Day progress', + 'back': showMainMenu + }, + 'Enable while locked': { + value: config.dayProgress.enabledLocked, + onchange: value => { + config.dayProgress.enableLocked = value; + saveSettings(); + } + }, + 'Enable while unlocked': { + value: config.dayProgress.enabledUnlocked, + onchange: value => { + config.dayProgress.enabledUnlocked = value; + saveSettings(); + } + }, + 'Color': { + value: COLOR_OPTIONS.map(item => colorString(item.val)).indexOf(colorString(config.dayProgress.color)), + format: value => COLOR_OPTIONS[value].name, + min: 0, + max: COLOR_OPTIONS.length - 1, + wrap: false, + onchange: value => { + config.dayProgress.color = COLOR_OPTIONS[value].val; + saveSettings(); + } + }, + 'Start hour': { + value: Math.floor(config.dayProgress.start / 100), + format: hourToString, + min: 0, + max: 23, + wrap: true, + onchange: hour => { + minute = config.dayProgress.start % 100; + config.dayProgress.start = (100 * hour) + minute; + saveSettings(); + } + }, + 'Start minute': { + value: config.dayProgress.start % 100, + min: 0, + max: 59, + wrap: true, + onchange: minute => { + hour = Math.floor(config.dayProgress.start / 100); + config.dayProgress.start = (100 * hour) + minute; + saveSettings(); + } + }, + 'End hour': { + value: Math.floor(config.dayProgress.end / 100), + format: hourToString, + min: 0, + max: 23, + wrap: true, + onchange: hour => { + minute = config.dayProgress.end % 100; + config.dayProgress.end = (100 * hour) + minute; + saveSettings(); + } + }, + 'End minute': { + value: config.dayProgress.end % 100, + min: 0, + max: 59, + wrap: true, + onchange: minute => { + hour = Math.floor(config.dayProgress.end / 100); + config.dayProgress.end = (100 * hour) + minute; + saveSettings(); + } + }, + 'Reset hour': { + value: Math.floor(config.dayProgress.reset / 100), + format: hourToString, + min: 0, + max: 23, + wrap: true, + onchange: hour => { + minute = config.dayProgress.reset % 100; + config.dayProgress.reset = (100 * hour) + minute; + saveSettings(); + } + }, + 'Reset minute': { + value: config.dayProgress.reset % 100, + min: 0, + max: 59, + wrap: true, + onchange: minute => { + hour = Math.floor(config.dayProgress.reset / 100); + config.dayProgress.reset = (100 * hour) + minute; + saveSettings(); + } + } + }); + }, + 'Low battery color': () => { + E.showMenu({ + '': { + 'title': 'Low battery color', + back: showMainMenu + }, + 'Low battery threshold': { + value: config.lowBattColor.level, + min: 0, + max: 100, + format: value => `${value}%`, + onchange: value => { + config.lowBattColor.level = value; + saveSettings(); + } + }, + 'Color': { + value: COLOR_OPTIONS.map(item => colorString(item.val)).indexOf(colorString(config.lowBattColor.color)), + format: value => COLOR_OPTIONS[value].name, + min: 0, + max: COLOR_OPTIONS.length - 1, + wrap: false, + onchange: value => { + config.lowBattColor.color = COLOR_OPTIONS[value].val; + saveSettings(); + } + } + }); + }, + }); + } + + showMainMenu(); +}); \ No newline at end of file diff --git a/apps/pomoplus/app.js b/apps/pomoplus/app.js new file mode 100644 index 000000000..73af5c935 --- /dev/null +++ b/apps/pomoplus/app.js @@ -0,0 +1,157 @@ +Bangle.POMOPLUS_ACTIVE = true; //Prevent the boot code from running. To avoid having to reload on every interaction, we'll control the vibrations from here when the user is in the app. + +const storage = require("Storage"); +const common = require("pomoplus-com.js"); + +//Expire the state if necessary +if ( + common.settings.pausedTimerExpireTime != 0 && + !common.state.running && + (new Date()).getTime() - common.state.pausedTime > common.settings.pausedTimerExpireTime +) { + common.state = common.STATE_DEFAULT; +} + +function drawButtons() { + //Draw the backdrop + const BAR_TOP = g.getHeight() - 24; + g.setColor(0, 0, 1).setFontAlign(0, -1) + .clearRect(0, BAR_TOP, g.getWidth(), g.getHeight()) + .fillRect(0, BAR_TOP, g.getWidth(), g.getHeight()) + .setColor(1, 1, 1); + + if (!common.state.wasRunning) { //If the timer was never started, only show a play button + g.drawImage(common.BUTTON_ICONS.play, g.getWidth() / 2, BAR_TOP); + } else { + g.drawLine(g.getWidth() / 2, BAR_TOP, g.getWidth() / 2, g.getHeight()); + if (common.state.running) { + g.drawImage(common.BUTTON_ICONS.pause, g.getWidth() / 4, BAR_TOP) + .drawImage(common.BUTTON_ICONS.skip, g.getWidth() * 3 / 4, BAR_TOP); + } else { + g.drawImage(common.BUTTON_ICONS.reset, g.getWidth() / 4, BAR_TOP) + .drawImage(common.BUTTON_ICONS.play, g.getWidth() * 3 / 4, BAR_TOP); + } + } +} + +function drawTimerAndMessage() { + g.reset() + .setFontAlign(0, 0) + .setFont("Vector", 36) + .clearRect(0, 24, 176, 152) + + //Draw the timer + .drawString((() => { + let timeLeft = common.getTimeLeft(); + let hours = timeLeft / 3600000; + let minutes = (timeLeft % 3600000) / 60000; + let seconds = (timeLeft % 60000) / 1000; + + function pad(number) { + return ('00' + parseInt(number)).slice(-2); + } + + if (hours >= 1) return `${parseInt(hours)}:${pad(minutes)}:${pad(seconds)}`; + else return `${parseInt(minutes)}:${pad(seconds)}`; + })(), g.getWidth() / 2, g.getHeight() / 2) + + //Draw the phase label + .setFont("Vector", 12) + .drawString(((currentPhase, numShortBreaks) => { + if (!common.state.wasRunning) return "Not started"; + else if (currentPhase == common.PHASE_WORKING) return `Work ${numShortBreaks + 1}/${common.settings.numShortBreaks + 1}` + else if (currentPhase == common.PHASE_SHORT_BREAK) return `Short break ${numShortBreaks + 1}/${common.settings.numShortBreaks}`; + else return "Long break!"; + })(common.state.phase, common.state.numShortBreaks), + g.getWidth() / 2, g.getHeight() / 2 + 18); + + //Update phase with vibation if needed + if (common.getTimeLeft() <= 0) { + common.nextPhase(true); + } +} + +drawButtons(); +Bangle.on("touch", (button, xy) => { + //If we support full touch and we're not touching the keys, ignore. + //If we don't support full touch, we can't tell so just assume we are. + if (xy !== undefined && xy.y <= g.getHeight() - 24) return; + + if (!common.state.wasRunning) { + //If we were never running, there is only one button: the start button + let now = (new Date()).getTime(); + common.state = { + wasRunning: true, + running: true, + startTime: now, + pausedTime: now, + elapsedTime: 0, + phase: common.PHASE_WORKING, + numShortBreaks: 0 + }; + setupTimerInterval(); + drawButtons(); + + } else if (common.state.running) { + //If we are running, there are two buttons: pause and skip + if (button == 1) { + //Record the exact moment that we paused + let now = (new Date()).getTime(); + common.state.pausedTime = now; + + //Stop the timer + common.state.running = false; + clearInterval(timerInterval); + timerInterval = undefined; + drawTimerAndMessage(); + drawButtons(); + + } else { + common.nextPhase(false); + } + + } else { + //If we are stopped, there are two buttons: Reset and continue + if (button == 1) { + //Reset the timer + common.state = common.STATE_DEFAULT; + drawTimerAndMessage(); + drawButtons(); + + } else { + //Start the timer and record old elapsed time and when we started + let now = (new Date()).getTime(); + common.state.elapsedTime += common.state.pausedTime - common.state.startTime; + common.state.startTime = now; + common.state.running = true; + drawTimerAndMessage(); + setupTimerInterval(); + drawButtons(); + } + } +}); + +let timerInterval; + +function setupTimerInterval() { + if (timerInterval !== undefined) { + clearInterval(timerInterval); + } + setTimeout(() => { + timerInterval = setInterval(drawTimerAndMessage, 1000); + drawTimerAndMessage(); + }, common.timeLeft % 1000); +} + +drawTimerAndMessage(); +if (common.state.running) { + setupTimerInterval(); +} + +//Save our state when the app is closed +E.on('kill', () => { + storage.writeJSON(common.STATE_PATH, common.state); +}); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); \ No newline at end of file diff --git a/apps/pomoplus/boot.js b/apps/pomoplus/boot.js new file mode 100644 index 000000000..edc233853 --- /dev/null +++ b/apps/pomoplus/boot.js @@ -0,0 +1,19 @@ +const POMOPLUS_storage = require("Storage"); +const POMOPLUS_common = require("pomoplus-com.js"); + +function setNextTimeout() { + setTimeout(() => { + //Make sure that the pomoplus app isn't in the foreground. The pomoplus app handles the vibrations when it is in the foreground in order to avoid having to reload every time the user changes state. That means that when the app is in the foreground, we shouldn't do anything here. + //We do this after the timer rather than before because the timer will start before the app executes. + if (Bangle.POMOPLUS_ACTIVE === undefined) { + POMOPLUS_common.nextPhase(true); + setNextTimeout(); + POMOPLUS_storage.writeJSON(POMOPLUS_common.STATE_PATH, POMOPLUS_common.state) + } + }, POMOPLUS_common.getTimeLeft()); +} + +//Only start the timeout if the timer is running +if (POMOPLUS_common.state.running) { + setNextTimeout(); +} \ No newline at end of file diff --git a/apps/pomoplus/common.js b/apps/pomoplus/common.js new file mode 100644 index 000000000..b1cd42de8 --- /dev/null +++ b/apps/pomoplus/common.js @@ -0,0 +1,118 @@ +const storage = require("Storage"); +const heatshrink = require("heatshrink"); + +exports.STATE_PATH = "pomoplus.state.json"; +exports.SETTINGS_PATH = "pomoplus.json"; + +exports.PHASE_WORKING = 0; +exports.PHASE_SHORT_BREAK = 1; +exports.PHASE_LONG_BREAK = 2; + +exports.BUTTON_ICONS = { + play: heatshrink.decompress(atob("jEYwMAkAGBnACBnwCBn+AAQPgAQPwAQP8AQP/AQXAAQPwAQP8AQP+AQgICBwQUCEAn4FggyBHAQ+CIgQ")), + pause: heatshrink.decompress(atob("jEYwMA/4BBAX4CEA")), + reset: heatshrink.decompress(atob("jEYwMA/4BB/+BAQPDAQPnAQIAKv///0///8j///EP//wAQQICBwQUCEhgyCHAQ+CIgI=")), + skip: heatshrink.decompress(atob("jEYwMAwEIgHAhkA8EOgHwh8A/EPwH8h/A/0P8H/h/w/+P/H/5/8//v/3/AAoICBwQUCDQIgCEwQsCGQQ4CHwRECA")) +}; + +exports.settings = storage.readJSON(exports.SETTINGS_PATH); +if (!exports.settings) { + exports.settings = { + workTime: 1500000, //Work for 25 minutes + shortBreak: 300000, //5 minute short break + longBreak: 900000, //15 minute long break + numShortBreaks: 3, //3 short breaks for every long break + pausedTimerExpireTime: 21600000, //If the timer was left paused for >6 hours, reset it on next launch + widget: false //If a widget is added in the future, whether the user wants it + }; +} + +//Store the minimal amount of information to be able to reconstruct the state of the timer at any given time. +//This is necessary because it is necessary to write to flash to let the timer run in the background, so minimizing the writes is necessary. +exports.STATE_DEFAULT = { + wasRunning: false, //If the timer ever was running. Used to determine whether to display a reset button + running: false, //Whether the timer is currently running + startTime: 0, //When the timer was last started. Difference between this and now is how long timer has run continuously. + pausedTime: 0, //When the timer was last paused. Used for expiration and displaying timer while paused. + elapsedTime: 0, //How much time the timer had spent running before the current start time. Update on pause or user skipping stages. + phase: exports.PHASE_WORKING, //What phase the timer is currently in + numShortBreaks: 0 //Number of short breaks that have occured so far +}; +exports.state = storage.readJSON(exports.STATE_PATH); +if (!exports.state) { + exports.state = exports.STATE_DEFAULT; +} + +//Get the number of milliseconds until the next phase change +exports.getTimeLeft = function () { + if (!exports.state.wasRunning) { + //If the timer never ran, the time left is just the amount of work time. + return exports.settings.workTime; + } else if (exports.state.running) { + //If the timer is running, the time left is current time - start time + preexisting time + var runningTime = (new Date()).getTime() - exports.state.startTime + exports.state.elapsedTime; + } else { + //If the timer is not running, the same as above but use when the timer was paused instead of now. + var runningTime = exports.state.pausedTime - exports.state.startTime + exports.state.elapsedTime; + } + + if (exports.state.phase == exports.PHASE_WORKING) { + return exports.settings.workTime - runningTime; + } else if (exports.state.phase == exports.PHASE_SHORT_BREAK) { + return exports.settings.shortBreak - runningTime; + } else { + return exports.settings.longBreak - runningTime; + } +} + +//Get the next phase to change to +exports.getNextPhase = function () { + if (exports.state.phase == exports.PHASE_WORKING) { + if (exports.state.numShortBreaks < exports.settings.numShortBreaks) { + return exports.PHASE_SHORT_BREAK; + } else { + return exports.PHASE_LONG_BREAK; + } + } else { + return exports.PHASE_WORKING; + } +} + +//Change to the next phase and update numShortBreaks, and optionally vibrate. DOES NOT WRITE STATE CHANGE TO STORAGE! +exports.nextPhase = function (vibrate) { + a = { + startTime: 0, //When the timer was last started. Difference between this and now is how long timer has run continuously. + pausedTime: 0, //When the timer was last paused. Used for expiration and displaying timer while paused. + elapsedTime: 0, //How much time the timer had spent running before the current start time. Update on pause or user skipping stages. + phase: exports.PHASE_WORKING, //What phase the timer is currently in + numShortBreaks: 0 //Number of short breaks that have occured so far + } + let now = (new Date()).getTime(); + exports.state.startTime = now; //The timer is being reset, so say it starts now. + exports.state.pausedTime = now; //This prevents a paused timer from having the start time moved to the future and therefore having been run for negative time. + exports.state.elapsedTime = 0; //Because we are resetting the timer, we no longer need to care about whether it was paused previously. + + let oldPhase = exports.state.phase; //Cache the old phase because we need to remember it when counting the number of short breaks + exports.state.phase = exports.getNextPhase(); + + if (oldPhase == exports.PHASE_SHORT_BREAK) { + //If we just left a short break, increase the number of short breaks + exports.state.numShortBreaks++; + } else if (oldPhase == exports.PHASE_LONG_BREAK) { + //If we just left a long break, set the number of short breaks to zero + exports.state.numShortBreaks = 0; + } + + if (vibrate) { + if (exports.state.phase == exports.PHASE_WORKING) { + Bangle.buzz(750, 1); + } else if (exports.state.phase == exports.PHASE_SHORT_BREAK) { + Bangle.buzz(); + setTimeout(Bangle.buzz, 400); + } else { + Bangle.buzz(); + setTimeout(Bangle.buzz, 400); + setTimeout(Bangle.buzz, 600); + } + } +} \ No newline at end of file diff --git a/apps/pomoplus/icon.js b/apps/pomoplus/icon.js new file mode 100644 index 000000000..020df6f5c --- /dev/null +++ b/apps/pomoplus/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwgQNhvQFCoXX7ooQFy0N7vdCYQDDIJ4YDC6QwC7oDBDwYcLN4QRDAApELEYYWGBQKEFCAoWKBIRaIBIIFEEA5iEEooUEDgYhEFxgDB6BfFGAgeFCAYXCBhAEJGYYrGMxQJDC4aIHHIjhGBQQXNE5L5DCIq3GIgiuHWQ7SHhoXKABRCBC6plDC6xVKJBgXVGIIWVAH5pTQK4X/cRAXvJCnQC7JIUCwQwTFwYwTCwgwSC4owQIwowQCw4wPCxAYNFxIYMCxgYJCpoZHBpI=")) diff --git a/apps/pomoplus/icon.png b/apps/pomoplus/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4ea72f270d5633755b90ede38c67cdc7e121e4c5 GIT binary patch literal 2122 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 IIVCg!009H(%m4rY literal 0 HcmV?d00001 diff --git a/apps/pomoplus/img/play.png b/apps/pomoplus/img/play.png new file mode 100644 index 0000000000000000000000000000000000000000..6c20c24c54d72382a69d5aa3685e3ad8fa6174ba GIT binary patch literal 2891 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x}o+U~I{Bb`J1#c2+1T%1_J8No8Qr zm{>c}*5j~)%+dJZrAngg+8q`tEBwU%ILU0~a$O;i)fy)2qxZK-jn}iQd+~#)f)B|X zUp;uVW_9yw1&+D~3oA>_T^^nPy}5LgY%Ja#-(B6mySyPl-}vk+31*YKX2G31W}IBt zwJ@CJV!yyKLuKRBGbS%lsX2b#mZ@fM_eY)o#r1u1rs;+X3PR_N4sYo+?^tf0+x*$C zuthX=>W?`USC()K*%!rr{Lx!{Ftst=?MzA5JPRisv0D+D$zdj@k2D{xSoLy>eu_<) zWq#qcQ=!-PsMjZ2EMKovJolM^P{a`-m5zV_SI*QM9T!(kPEvIJT`2#5!RzTKmQGmB z;?~C+vcR$I?}PdeyQ8)3Eg!13K6ZHC{kVpQd135=z~VXYlaFW4VK|unz$^c!c4@-1 z$zP(pyX6@7-ac@&)I0cF!)e)s2PY@^-kjQG(pn=|VZS*46jSYXhwrnlM;FU4=XaR3 z%j+Hkd;0;8#!c62@7=w6@Am%mS%3dB99mg)Jm;_40${YTC3(BM0BIoj>AbrhNO2Z; zL>4nJ=qZCRW5rVYGN2%PiKnkC`!i-yc1y0~8~!E(g(OQ{BTAg}b8}PkN*J7rQWHy3 zQxwWGOEMJPJ$(bh8~Mb6W+{8RIEHxeGD>hh{|3|p0snyj#-=9C2r~@X0!AQ!iBn3$ z4MMg6W+*i*!fOFFEF#JRN-Sc6X(ooo7L0`Sk>mqp!-$O^vMqpFM#v(HEg)nO)hxhe z5!Ed~w}_-v1k+3m4NGw}vjFA@nppr#T`Vx0s71pJhM7k-3(yUwngzHFrq}{P2E!~M zE0T#d9ApVeaX^Z}FdqmdKI;Vst0LE7sJpcdz literal 0 HcmV?d00001 diff --git a/apps/pomoplus/img/reset.png b/apps/pomoplus/img/reset.png new file mode 100644 index 0000000000000000000000000000000000000000..7a317d09795c09aabab4836c8b9ec4a6c5fe4db8 GIT binary patch literal 2891 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x}o+U~I{Bb`J1#c2+1T%1_J8No8Qr zm{>c}*5j~)%+dJZrAngg+8q`tEBwU%ILU0~a$O;i)fy)2qxZK-jn}iQd+~#)f)B|X zUp;uVW_9yw1&+D~3oA>_T^^nPy}5LgY%Ja#-(B6mySyPl-}vk+31*YKX2G31W}IBt zwJ@CJV!yyKLuKRBGbS%lsX2b#mZ@fM_eY)o#r1u1rs;+X3PR_N4sYo+?^tf0+x*$C zuthX=>W?`USC()K*%!rr{Lx!{Ftst=?MzA5JPRisv0D+D$zdj@k2D{xSoLy>eu_<) zWq#qcQ=!-PsMjZ2EMKovJolM^P{a`-m5zV_SI*QM9T!(kPEvIJT`2#5!RzTKmQGmB z;?~C+vcR$I?}PdeyQ8)3Eg!13K6ZHC{kVpQd135=z~VXYlaFW4VK|unz$^c!c4@-1 z$zP(pyX6@7-ac@&)I0cF!)e)s2PY@^-kjQG(pn=|VZS*46jSYXhwrnlM;FU4=XaR3 z%j+Hkd;0;8#!c62@7=w6@Am%mS%3dB99mg)Jm;_40${YTC3(BM0BIoj>AbrhNO2Z; zL>4nJ=qZCRW5rVYGN2%PiKnkC`!i-y4rWEypL5fJLXst}5hc#~xw)x%B@E6*sfi`2 zDGKG8B^e6tp1uL$jeO!jvy?qu978;K86`NMe`EX)1VD{A0V5FLlmto;($9oXGe{1f z0r=!#<`T33mnFm)4$@1M1?ZL#YdAG9F5Ihr6 z+Y*@Ba0@^#qn0Hw!$D@ESU?R+kPQc!NApyK;scrn5w#2l1q%qkf(q;dY8wu*0%FN% zSp*9WoHWgoDM=Q9QU(a%bS@SNqAfr+7@3X5OcWuaEWlc}*5j~)%+dJZrAngg+8q`tEBwU%ILU0~a$O;i)fy)2qxZK-jn}iQd+~#)f)B|X zUp;uVW_9yw1&+D~3oA>_T^^nPy}5LgY%Ja#-(B6mySyPl-}vk+31*YKX2G31W}IBt zwJ@CJV!yyKLuKRBGbS%lsX2b#mZ@fM_eY)o#r1u1rs;+X3PR_N4sYo+?^tf0+x*$C zuthX=>W?`USC()K*%!rr{Lx!{Ftst=?MzA5JPRisv0D+D$zdj@k2D{xSoLy>eu_<) zWq#qcQ=!-PsMjZ2EMKovJolM^P{a`-m5zV_SI*QM9T!(kPEvIJT`2#5!RzTKmQGmB z;?~C+vcR$I?}PdeyQ8)3Eg!13K6ZHC{kVpQd135=z~VXYlaFW4VK|unz$^c!c4@-1 z$zP(pyX6@7-ac@&)I0cF!)e)s2PY@^-kjQG(pn=|VZS*46jSYXhwrnlM;FU4=XaR3 z%j+Hkd;0;8#!c62@7=w6@Am%mS%3dB99mg)Jm;_40${YTC3(BM0BIoj>AbrhNO2Z; zL>4nJ=qZCRW5rVYGN2%PiKnkC`!i-y4mSQL5h-thLXst}5hc#~xw)x%B@E6*sfi`2 zDGKG8B^e6tp1uL$jeO!jvy?qu978;K86`NMe`EL$1VD{M15(v9flMY<6DjJ!7SPfX zxCOMb1jPbcSb|{zwJpJF0W~ebX#uq?!D|6EEFowCrIrw70VS3&l9DSy7Lf{w_5rB| z!_<>x0V5E=G!jFD)Dvw1IfjEAL6imL8cvi2lo(FX0!j_XYXLP3$7unz4998#H4VqG mfZB$mSU?NIK^D-oMFBE@re=!7?Z%8XAhxHgpUXO@geCy$z({uh literal 0 HcmV?d00001 diff --git a/apps/pomoplus/metadata.json b/apps/pomoplus/metadata.json new file mode 100644 index 000000000..fcacae35d --- /dev/null +++ b/apps/pomoplus/metadata.json @@ -0,0 +1,37 @@ +{ + "id": "pomoplus", + "name": "Pomodoro Plus", + "version": "0.05", + "description": "A configurable pomodoro timer that runs in the background.", + "icon": "pomodoro.png", + "type": "app", + "tags": "pomodoro,cooking,tools", + "supports": [ + "BANGLEJS", + "BANGLEJS2" + ], + "allow_emulator": true, + "storage": [ + { + "name": "pomoplus.app.js", + "url": "app.js" + }, + { + "name": "pomoplus.img", + "url": "icon.js", + "evaluate": true + }, + { + "name": "pomoplus.boot.js", + "url": "boot.js" + }, + { + "name": "pomoplus-com.js", + "url": "common.js" + }, + { + "name": "pomoplus.settings.js", + "url": "settings.js" + } + ] +} \ No newline at end of file diff --git a/apps/pomoplus/settings.js b/apps/pomoplus/settings.js new file mode 100644 index 000000000..1ff52340a --- /dev/null +++ b/apps/pomoplus/settings.js @@ -0,0 +1,94 @@ +const SETTINGS_PATH = 'pomoplus.json'; +const storage = require("Storage"); + +(function (back) { + let settings = storage.readJSON(SETTINGS_PATH); + if (!settings) { + settings = { + workTime: 1500000, //Work for 25 minutes + shortBreak: 300000, //5 minute short break + longBreak: 900000, //15 minute long break + numShortBreaks: 3, //3 short breaks for every long break + pausedTimerExpireTime: 21600000, //If the timer was left paused for >6 hours, reset it on next launch + widget: false //If a widget is added in the future, whether the user wants it + }; + } + + function save() { + storage.writeJSON(SETTINGS_PATH, settings); + } + + const menu = { + '': { 'title': 'Pomodoro Plus' }, + '< Back': back, + 'Work time': { + value: settings.workTime, + step: 60000, //1 minute + min: 60000, + // max: 10800000, + // wrap: true, + onchange: function (value) { + settings.workTime = value; + save(); + }, + format: function (value) { + return '' + (value / 60000) + 'm' + } + }, + 'Short break time': { + value: settings.shortBreak, + step: 60000, + min: 60000, + // max: 10800000, + // wrap: true, + onchange: function (value) { + settings.shortBreak = value; + save(); + }, + format: function (value) { + return '' + (value / 60000) + 'm' + } + }, + '# Short breaks': { + value: settings.numShortBreaks, + step: 1, + min: 0, + // max: 10800000, + // wrap: true, + onchange: function (value) { + settings.numShortBreaks = value; + save(); + } + }, + 'Long break time': { + value: settings.longBreak, + step: 60000, + min: 60000, + // max: 10800000, + // wrap: true, + onchange: function (value) { + settings.longBreak = value; + save(); + }, + format: function (value) { + return '' + (value / 60000) + 'm' + } + }, + 'Timer expiration': { + value: settings.pausedTimerExpireTime, + step: 900000, //15 minutes + min: 0, + // max: 10800000, + // wrap: true, + onchange: function (value) { + settings.pausedTimerExpireTime = value; + save(); + }, + format: function (value) { + if (value == 0) return "Off" + else return `${Math.floor(value / 3600000)}h ${(value % 3600000) / 60000}m` + } + }, + }; + E.showMenu(menu) +}) \ No newline at end of file diff --git a/apps/random/app.js b/apps/random/app.js new file mode 100644 index 000000000..c3001a6d1 --- /dev/null +++ b/apps/random/app.js @@ -0,0 +1,205 @@ +let n = 1; +let diceSides = 6; +let replacement = false; +let min = 1; +let max = 10; + +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +function showCoinMenu() { + E.showMenu({ + '': { + 'title': 'Coin flip', + 'back': showMainMenu + }, + '# of coins': { + value: n, + step: 1, + min: 1, + onchange: value => n = value + }, + 'Go': () => { + let resultMenu = { + '': { + 'title': 'Result', + 'back': showCoinMenu + } + }; + let heads = 0; + for (let i = 0; i < n; i++) { + let coin = Math.random() < 0.5; + if (coin) heads++; + resultMenu[`${i + 1}: ${coin ? 'Heads' : 'Tails'}`] = () => { }; + } + let tails = n - heads; + resultMenu[`${heads} heads, ${Math.round(100 * heads / n)}%`] = () => { }; + resultMenu[`${tails} tails, ${Math.round(100 * tails / n)}%`] = () => { }; + + E.showMenu(resultMenu); + } + }); +} + + +function showDiceMenu() { + E.showMenu({ + '': { + 'title': 'Dice roll', + 'back': showMainMenu + }, + '# of dice': { + value: n, + step: 1, + min: 1, + onchange: value => n = value + }, + '# of sides': { + value: diceSides, + step: 1, + min: 2, + onchange: value => diceSides = value + }, + 'Go': () => { + let resultMenu = { + '': { + 'title': 'Result', + 'back': showDiceMenu + } + }; + let sum = 0; + let min = diceSides + 1; + let max = 0; + for (let i = 0; i < n; i++) { + let roll = Math.floor(Math.random() * diceSides + 1); + sum += roll; + if (roll < min) min = roll; + if (roll > max) max = roll; + resultMenu[`${i + 1}: ${roll}`] = () => { }; + } + resultMenu[`Sum: ${sum}`] = () => { }; + resultMenu[`Min: ${min}`] = () => { }; + resultMenu[`Max: ${max}`] = () => { }; + resultMenu[`Average: ${sum / n}`] = () => { }; + + E.showMenu(resultMenu); + } + }); +} + + +function showCardMenu() { + E.showMenu({ + '': { + 'title': 'Card draw', + 'back': showMainMenu + }, + '# of cards': { + value: Math.min(52, n), + step: 1, + min: 1, + max: 52, + onchange: value => n = value + }, + 'Replacement': { + value: replacement, + onchange: value => { + replacement = value; + if (replacement && n > 52) n = 52; + } + }, + 'Go': () => { + n = Math.min(n, 52); + SUITS = ['Spades', 'Diamonds', 'Clubs', 'Hearts']; + RANKS = ['Ace', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King']; + class Card { + constructor(suit, rank) { + this.suit = suit; + this.rank = rank; + } + + //Can't use == to check equality, so using Java-inspired .equals() + equals(other) { + return this.suit == other.suit && this.rank == other.rank; + } + } + + let resultMenu = { + '': { + 'title': 'Result', + 'back': showCardMenu + } + }; + let cards = []; + for (let i = 0; i < n; i++) { + let newCard; + while (true) { + newCard = new Card( + SUITS[Math.floor(Math.random() * SUITS.length)], + RANKS[Math.floor(Math.random() * RANKS.length)]); + + if (replacement) break; //If we are doing replacement, skip the check for duplicates and stop looping + + if (!cards.map(card => card.equals(newCard)).includes(true)) break; //If there are no duplicates found, stop looping + } + + cards.push(newCard); + resultMenu[`${newCard.rank} of ${newCard.suit}`] = () => { }; + } + + E.showMenu(resultMenu); + } + }); +} + +function showNumberMenu() { + E.showMenu({ + '': { + 'title': 'Number choice', + 'back': showMainMenu + }, + 'Minimum': { + value: min, + step: 1, + onchange: value => min = value + }, + 'Maximum': { + value: max, + step: 1, + onchange: value => max = value + }, + '# of choices': { + value: n, + min: 1, + step: 1, + onchange: value => n = value + }, + 'Go': () => { + let resultMenu = { + '': { + 'title': 'Result', + 'back': showNumberMenu + } + }; + for (let i = 0; i < n; i++) { + let value = Math.floor(min + Math.random() * (max - min + 1)); + resultMenu[`${i + 1}: ${value}`] = () => { }; + } + E.showMenu(resultMenu); + } + }); +} + +function showMainMenu() { + E.showMenu({ + '': { + 'title': 'Random' + }, + 'Coin': showCoinMenu, + 'Dice': showDiceMenu, + 'Card': showCardMenu, + 'Number': showNumberMenu + }); +} + +showMainMenu(); \ No newline at end of file diff --git a/apps/random/icon.js b/apps/random/icon.js new file mode 100644 index 000000000..de84a0893 --- /dev/null +++ b/apps/random/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwIEBgf///AAoMHAoPgAoMPAoPwAoMfAoP4AoM/AoP8AoN/AoP+AoIEBAAMAgIbBD4OAAoPgFYIFC4A3BAoQCFEAQFBEwV/AoIyCn+ALYYFFCIIFDDoIECFIQFCGoQFCIIQFCJoQFCNoIuEHwQuCHwQuCQYQuCR4QuCTYQuGAoIcDg4oEg4oEg6mCAoQuDAoIuDAFQvFAsIA==")) \ No newline at end of file diff --git a/apps/random/icon.png b/apps/random/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e4af7d7a19d5228f8758605027b3c506d0fa4c77 GIT binary patch literal 378 zcmV-=0fqjFP)sE>U;ut)p4tfn;FzDPnNEiEK2=o<)73=@l|)GEJl_#* zl$1?^bb6QUus%x6BtRPI3t=b+N{+-)JTlMjM9B`M%rg)+09(Ptxw~#J4`7dKdJLRS zAoDNHWjnx_UlxEhza)TSemMZu{89i>^S5Nq>jcEa&CdiVF+U4HH80&w(qUt)O3hby zpxk^Vz!dYV01S=sQ1H!8upJoAKP=FJU;rYyBO(_N2q2a>CUk { + if (entryTerminated) { + if (liftOnNumberPress) liftStack(); + x = '0.'; + entryTerminated = false; + liftOnNumberPress = false; + feedback(true); + updateDisplay(); + } else if (!x.includes('.')) { + x += '.'; + feedback(true); + updateDisplay(); + } else { + feedback(false); + } + } +}; + +class ModeButton { + constructor(currentMode) { + if (currentMode == 'memstore' || currentMode == 'memrec') { + this.label = 'Exit'; + } else if (currentMode == 'operation') { + this.label = 'Num'; + } else { + this.label = 'Op'; + } + } + + onclick() { + if (mode == 'memstore' || mode == 'memrec') { + mode = 'operation'; + } else if (mode == 'operation') { + mode = 'number'; + } else { + mode = 'operation'; + } + feedback(true); + drawButtons(); + } +} + +class OperationButton { + constructor(label) { + this.label = label; + } + + onclick() { + if (this.label == '/' && parseFloat(x) == 0) { + feedback(false); + return; + } + let result = this.getResult(); + x = '' + result; + y = z; + z = t; + entryTerminated = true; + liftOnNumberPress = true; + feedback(true); + updateDisplay(); + } + + getResult() { + let numX = parseFloat(x); + return { + '+': y + numX, + '-': y - numX, + '/': y / numX, + '*': y * numX, + '^': Math.pow(y, numX) + }[this.label]; + } +} + +class OneNumOpButton { + constructor(label) { + this.label = label; + } + + onclick() { + result = { + '+-': '' + -parseFloat(x), + 'Sin': '' + Math.sin(parseFloat(x)), + 'Cos': '' + Math.cos(parseFloat(x)), + 'Tan': '' + Math.tan(parseFloat(x)), + 'Asin': '' + Math.asin(parseFloat(x)), + 'Acos': '' + Math.acos(parseFloat(x)), + 'Atan': '' + Math.atan(parseFloat(x)), + 'Log': '' + (Math.log(parseFloat(x)) / Math.log(10)) + }[this.label]; + if (isNaN(result) || result == 'NaN') feedback(false); + else { + x = result; + entryTerminated = true; + liftOnNumberPress = true; + feedback(true); + updateDisplay(); + } + } +} + +let ClearButton = { + label: 'Clr', + onclick: () => { + if (x != '0') { + x = '0'; + updateDisplay(); + } else if (y != 0 || z != 0 || t != 0) { + y = 0; + z = 0; + t = 0; + E.showMessage('Registers cleared!'); + setTimeout(() => { + drawButtons(); + updateDisplay(); + }, 250); + } else { + memory = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + storage.writeJSON(MEMORY_FILE, memory); + E.showMessage('Memory cleared!'); + setTimeout(() => { + drawButtons(); + updateDisplay(); + }, 250); + } + entryTerminated = false; + liftOnNumberPress = false; + feedback(true); + } +}; + +let SwapButton = { + label: 'Swp', + onclick: () => { + oldX = x; + x = '' + y; + y = parseFloat(oldX); + entryTerminated = true; + liftOnNumberPress = true; + feedback(true); + updateDisplay(); + } +}; + +let RotateButton = { + label: 'Rot', + onclick: () => { + oldX = x; + x = '' + y; + y = z; + z = t; + t = parseFloat(oldX); + entryTerminated = true; + liftOnNumberPress = true; + feedback(true); + updateDisplay(); + } +}; + +let EnterButton = { + label: 'Ent', + onclick: () => { + liftStack(); + entryTerminated = true; + liftOnNumberPress = false; + feedback(true); + updateDisplay(); + } +}; + +let ScientificButton = { + label: 'Sci', + onclick: () => { + mode = 'scientific'; + feedback(true); + drawButtons(); + } +}; + +class ConstantButton { + constructor(label, value) { + this.label = label; + this.value = value; + } + + onclick() { + if (entryTerminated && liftOnNumberPress) liftStack(); + x = '' + this.value; + entryTerminated = true; + liftOnNumberPress = true; + feedback(true); + updateDisplay(); + } +} + +let MemStoreButton = { + label: 'Sto', + onclick: () => { + mode = 'memstore'; + feedback(true); + drawButtons(); + } +}; + +let MemRecallButton = { + label: 'Rec', + onclick: () => { + mode = 'memrec'; + feedback(true); + drawButtons(); + } +}; + +class MemStoreIn { + constructor(register) { + this.register = register; + this.label = '' + register; + } + + onclick() { + memory[this.register] = parseFloat(x); + storage.writeJSON(MEMORY_FILE, memory); + mode = 'scientific'; + entryTerminated = true; + liftOnNumberPress = true; + feedback(true); + drawButtons(); + } +} + +class MemRecFrom { + constructor(register) { + this.register = register; + this.label = '' + register; + } + + onclick() { + x = '' + memory[this.register]; + mode = 'scientific'; + entryTerminated = true; + liftOnNumberPress = true; + feedback(true); + updateDisplay(); + drawButtons(); + } +} + +const BUTTONS = { + 'number': [ + [new NumberButton(7), new NumberButton(8), new NumberButton(9), new ModeButton('number')], + [new NumberButton(4), new NumberButton(5), new NumberButton(6), new NumberButton(0)], + [new NumberButton(1), new NumberButton(2), new NumberButton(3), DecimalPointButton] + ], + 'operation': [ + [new OperationButton('+'), new OperationButton('-'), ClearButton, new ModeButton('operation')], + [new OperationButton('*'), new OperationButton('/'), SwapButton, EnterButton], + [new OperationButton('^'), new OneNumOpButton('+-'), RotateButton, ScientificButton] + ], + 'scientific': [ + [new OneNumOpButton('Sin'), new OneNumOpButton('Cos'), new OneNumOpButton('Tan'), new ModeButton('scientific')], + [new OneNumOpButton('Asin'), new OneNumOpButton('Acos'), new OneNumOpButton('Atan'), MemStoreButton], + [new OneNumOpButton('Log'), new ConstantButton('e', Math.E), new ConstantButton('pi', Math.PI), MemRecallButton] + ], + 'memstore': [ + [new MemStoreIn(7), new MemStoreIn(8), new MemStoreIn(9), new ModeButton('memstore')], + [new MemStoreIn(4), new MemStoreIn(5), new MemStoreIn(6), new MemStoreIn(0)], + [new MemStoreIn(1), new MemStoreIn(2), new MemStoreIn(3), new ModeButton('memstore')] + ], + 'memrec': [ + [new MemRecFrom(7), new MemRecFrom(8), new MemRecFrom(9), new ModeButton('memrec')], + [new MemRecFrom(4), new MemRecFrom(5), new MemRecFrom(6), new MemRecFrom(0)], + [new MemRecFrom(1), new MemRecFrom(2), new MemRecFrom(3), new ModeButton('memrec')] + ], +}; + +let x = '0'; +let y = 0; +let z = 0; +let t = 0; +let memJSON = storage.readJSON(MEMORY_FILE); +if (memJSON) { + let memory = memJSON; +} else { + let memory = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; +} +let mode = 'number'; +let entryTerminated = false; +let liftOnNumberPress = false; + +function liftStack() { + t = z; + z = y; + y = parseFloat(x); +} + +function feedback(acceptable) { + if (acceptable) Bangle.buzz(50, 0.5); + else Bangle.buzz(200, 1); +} + +function drawButtons() { + g.reset().clearRect(0, 44, 175, 175).setFont("Vector", 15).setFontAlign(0, 0); + //Draw lines + for (let x = 44; x <= 176; x += 44) { + g.drawLine(x, 44, x, 175); + } + for (let y = 44; y <= 176; y += 44) { + g.drawLine(0, y, 175, y); + } + for (let row = 0; row < 3; row++) { + for (let col = 0; col < 4; col++) { + g.drawString(BUTTONS[mode][row][col].label, 22 + 44 * col, 66 + 44 * row); + } + } +} + +function getFontSize(length) { + let size = Math.floor(176 / length); //Characters of width needed per pixel + size *= (20 / 12); //Convert to height + // Clamp to between 6 and 20 + if (size < 6) return 6; + else if (size > 20) return 20; + else return Math.floor(size); +} + +function updateDisplay() { + g.clearRect(0, 24, 175, 43).setColor(storage.readJSON('setting.json').theme.fg2).setFontAlign(1, -1).setFont("Vector", getFontSize(x.length)).drawString(x, 176, 24); +} + +Bangle.on("touch", (button, xy) => { + let row = Math.floor((xy.y - 44) / 44); + let col = Math.floor(xy.x / 44); + if (row < 0) { // Tap number to show registers + g.clearRect(0, 24, 175, 43).setColor(storage.readJSON('setting.json').theme.fg2).setFontAlign(1, -1) + .setFont("Vector", getFontSize(x.length)).drawString('' + t, 176, 24); + + g.clearRect(0, 44, 175, 63).setColor(storage.readJSON('setting.json').theme.fg2).setFontAlign(1, -1) + .setFont("Vector", getFontSize(x.length)).drawString('' + z, 176, 44); + + g.clearRect(0, 64, 175, 83).setColor(storage.readJSON('setting.json').theme.fg2).setFontAlign(1, -1) + .setFont("Vector", getFontSize(x.length)).drawString('' + y, 176, 64); + + g.clearRect(0, 84, 175, 103).setColor(storage.readJSON('setting.json').theme.fg2).setFontAlign(1, -1) + .setFont("Vector", getFontSize(x.length)).drawString(x, 176, 84); + + setTimeout(() => { + drawButtons(); + updateDisplay(); + }, 500); + } else { + if (row > 2) row = 2; + if (col < 0) col = 0; + if (col > 3) col = 3; + + BUTTONS[mode][row][col].onclick(); + } +}); + +Bangle.on("swipe", dir => { + if (dir == -1) { + if (entryTerminated) ClearButton.onclick(); + else if (x.length == 1) x = '0'; + else x = x.substring(0, x.length - 1); + + feedback(true); + updateDisplay(); + } else if (dir == 0) { + EnterButton.onclick(); + } +}); + +g.clear().reset(); + +drawButtons(); +updateDisplay(); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); \ No newline at end of file diff --git a/apps/rpnsci/icon.js b/apps/rpnsci/icon.js new file mode 100644 index 000000000..24ea29035 --- /dev/null +++ b/apps/rpnsci/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwcCkmSpICEpEEBAwCICP4CCk/yCP4RVyf/AAXkCK0///5Nf4RffcYR/AQkAAERr/CKn+CK9//+f/41O/mT5IRO/+eLJ8/CIw+BAAP8CIkn+QRQMQY1MCKM8z5rP8mf/KzO8mTCJ1/CIP/8j7pCP4RMA==")) \ No newline at end of file diff --git a/apps/rpnsci/icon.png b/apps/rpnsci/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..474abf7e3358c8f47326adacfdf4cd4bd2918cba GIT binary patch literal 765 zcmVEX>4Tx04R}tkv&MmKpe$iTcsiuQ9Fn@1guUL#ELj-6^c+H)C#RSm|Xe=O&XFE z7e~Rh;NZt%)xpJCR|i)?5c~jfbaGO3krMxx6k5c1aNLh~_a1le0DryARI_6OP&La) zCE`LRyD9`<5kNosFoKxGOnpuilkgm0_we!cF3PjK&;2=il$^-`pFljzbi*RvAfDc| zbk6(4VOEqB;&bA0gDyz?$aUG}H_ioz{X8>lq*L?6VPc`s#&R38qM;H`5l0kNqkMnH zWrgz=XSG~q&3p0}hH~1nGy0}1FmMZWuerT7_i_3Fq^Yaq4RCM> zj1?$*-Q(R|?Y;ebrrF;Qq{ni*j5N?100006VoOIv00000008+zyMF)x010qNS#tmY zE+YT{E+YYWr9XB6000McNliru<^vKDD+ff07Ipvt02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{007lVL_t(&-tCy(4udcVMvL+NUzy#k$)aO}W>o49Hzr1_ zhw}GTT2pOlCeLf$C$_e@0RX@(0M*=dX9oZPV9a(aVLv7FsozR5fZ1j_%;OmG7RUZn z%-hUD002;?3SC($2_XOgxG{jF_IY-|)dw_rgBj)k03f2wqGwO{oklJ3e!Tz7DRpG6 zubTLs7FP9stWX*4ApV~(B4|W%4t1kzT29*{FIV$^NK(e*e~v``k4DzL{u)Zl09YZD vmDuT>c$p;jcw+3pcXB62(4YqZ03g*KO-@5vd@SZ300000NkvXXu0mjfLa#qu literal 0 HcmV?d00001 diff --git a/apps/rpnsci/icon.xcf b/apps/rpnsci/icon.xcf new file mode 100644 index 0000000000000000000000000000000000000000..9a41dbe325b45a3a516fe41d2dd3bcab725a4fc4 GIT binary patch literal 4021 zcmd^C&ubGw6rN4mSd%7g?GF_^j8U<*ZfT;e-UNG44}xItx=ALR(PX#mZfqh#Jc{5^ z{|BMqMW~<`=|A92{{(Le9tGF$?as7YX+1;=p}ytK``&xAv-9Jdon2eD)_A8{=Z_Xk zB?ehkO86CY0%{m2CZQuM2$4djphM6j&>4lP-Zb*^5I)`E*6Y3qcvL@uW4OCA^*JHN z^Vk`>AKMWc4r@w;`Rtj0xqqjzFYoId&VQ<3-_^ZJ(O1SiUf8(i7D{x(;s!9)f?eZiiD3+I}GG zU0wyp1y!xM9kb=u1h1nP#90cg%Np2TzNFlSkai=0zfih*Wl04i=52SK`bt!#j?f@bXvWYoK+<1g8M3@=|Is?52#-n(u@%eFTn0c!-AsW{9&Tu z(sEgU { + let hours = Math.floor(time / 3600000); + let minutes = Math.floor((time % 3600000) / 60000); + let seconds = Math.floor((time % 60000) / 1000); + let hundredths = Math.floor((time % 1000) / 10); + + if (hours >= 1) return `${hours}:${pad(minutes)}:${pad(seconds)}`; + else return `${minutes}:${pad(seconds)}:${pad(hundredths)}`; + })(), g.getWidth() / 2, g.getHeight() / 2); + + //Draw the lap labels if necessary + if (lapHistory.splits.length >= 1) { + let lastLap = lapHistory.splits.length; + let curLap = lastLap + 1; + + g.setFont("Vector", 12) + .drawString((() => { + let lapTime = time - lapHistory.splits[lastLap - 1]; + let hours = Math.floor(lapTime / 3600000); + let minutes = Math.floor((lapTime % 3600000) / 60000); + let seconds = Math.floor((lapTime % 60000) / 1000); + let hundredths = Math.floor((lapTime % 1000) / 10); + + if (hours == 0) return `Lap ${curLap}: ${pad(minutes)}:${pad(seconds)}:${pad(hundredths)}`; + else return `Lap ${curLap}: ${hours}:${pad(minutes)}:${pad(seconds)}:${pad(hundredths)}`; + })(), g.getWidth() / 2, g.getHeight() / 2 + 18) + .drawString((() => { + let lapTime; + if (lastLap == 1) lapTime = lapHistory.splits[lastLap - 1]; + else lapTime = lapHistory.splits[lastLap - 1] - lapHistory.splits[lastLap - 2]; + let hours = Math.floor(lapTime / 3600000); + let minutes = Math.floor((lapTime % 3600000) / 60000); + let seconds = Math.floor((lapTime % 60000) / 1000); + let hundredths = Math.floor((lapTime % 1000) / 10); + + if (hours == 0) return `Lap ${lastLap}: ${pad(minutes)}:${pad(seconds)}:${pad(hundredths)}`; + else return `Lap ${lastLap}: ${hours}:${pad(minutes)}:${pad(seconds)}:${pad(hundredths)}`; + })(), g.getWidth() / 2, g.getHeight() / 2 + 30); + } +} + +drawButtons(); + +function firstTimeStart(now, time) { + state = { + wasRunning: true, + sessionStart: Math.floor(now), + running: true, + startTime: now, + pausedTime: 0, + elapsedTime: 0, + }; + lapFile = 'stlap-' + state.sessionStart + '.json'; + setupTimerInterval(); + Bangle.buzz(200); + drawButtons(); +} + +function split(now, time) { + lapHistory.splits.push(time); + Bangle.buzz(); +} + +function pause(now, time) { + //Record the exact moment that we paused + state.pausedTime = now; + + //Stop the timer + state.running = false; + stopTimerInterval(); + Bangle.buzz(200); + drawTime(); + drawButtons(); +} + +function reset(now, time) { + //Record the time + lapHistory.splits.push(time); + lapHistory.final = true; + storage.writeJSON(lapFile, lapHistory); + + //Reset the timer + state = STATE_DEFAULT; + lapHistory = { + final: false, + splits: [] + }; + Bangle.buzz(500); + drawTime(); + drawButtons(); +} + +function start(now, time) { + //Start the timer and record when we started + state.elapsedTime += (state.pausedTime - state.startTime); + state.startTime = now; + state.running = true; + setupTimerInterval(); + Bangle.buzz(200); + drawTime(); + drawButtons(); +} + +Bangle.on("touch", (button, xy) => { + //In gesture mode, just turn on the light and then return + if (gestureMode) { + Bangle.setLCDPower(true); + return; + } + + //If we support full touch and we're not touching the keys, ignore. + //If we don't support full touch, we can't tell so just assume we are. + if (xy !== undefined && xy.y <= g.getHeight() - 48) return; + + let now = (new Date()).getTime(); + let time = getTime(); + + if (!state.wasRunning) { + if (storage.read('stlapview.app.js') !== undefined) { + //If we were never running and stlapview is installed, there are two buttons: open stlapview and start the timer + if (button == 1) load('stlapview.app.js'); + else firstTimeStart(now, time); + } + //If stlapview there is only one button: the start button + else firstTimeStart(now, time); + } else if (state.running) { + //If we are running, there are two buttons: lap and pause + if (button == 1) split(now, time); + else pause(now, time); + + } else { + //If we are stopped, there are two buttons: reset and continue + if (button == 1) reset(now, time); + else start(now, time); + } +}); + +Bangle.on('swipe', direction => { + let now = (new Date()).getTime(); + let time = getTime(); + + if (gestureMode) { + Bangle.setLCDPower(true); + if (!state.wasRunning) firstTimeStart(now, time); + else if (state.running) pause(now, time); + else start(now, time); + } else { + gestureMode = true; + Bangle.setOptions({ + lockTimeout: 0 + }); + drawTime(); + drawButtons(); + } +}); + +setWatch(() => { + let now = (new Date()).getTime(); + let time = getTime(); + + if (gestureMode) { + Bangle.setLCDPower(true); + if (state.running) split(now, time); + else reset(now, time); + } +}, BTN1, { repeat: true }); + +let timerInterval; + +function setupTimerInterval() { + if (timerInterval !== undefined) { + clearInterval(timerInterval); + } + timerInterval = setInterval(drawTime, 10); +} + +function stopTimerInterval() { + if (timerInterval !== undefined) { + clearInterval(timerInterval); + timerInterval = undefined; + } +} + +drawTime(); +if (state.running) { + setupTimerInterval(); +} + +//Save our state when the app is closed +E.on('kill', () => { + storage.writeJSON(STATE_PATH, state); + if (state.wasRunning) { + storage.writeJSON(lapFile, lapHistory); + } +}); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); \ No newline at end of file diff --git a/apps/stlap/icon.js b/apps/stlap/icon.js new file mode 100644 index 000000000..32281b7ab --- /dev/null +++ b/apps/stlap/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4UA///vvvvEF/muH+cDHgPABf4AElWoKhILClALH1WqAQIWHBYIABwAKEgQKD1WgBYkK1X1r4XHlWtqtVvQLG1XVBYNXHYsC1YJBBoPqC4kKEQILCvQ7EhW1BYdeBYkqytVqwCCQwkqCgILCq4LFIoILCqoLEIwIsBGQJIBBZ+pA4Na0oDBtQLGvSFCBaYjIHYR3CI5AADBYhrCAAaDHAASDGQASGCBYizCAASzFZYQACZYrjCIwb7QHgIkCvQ6EGAWq+tf1QuEGAWqAAQuFEgQKBEQw9DHIwAuA=")) diff --git a/apps/stlap/icon.png b/apps/stlap/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..92ffe73b7f172f7019486231d5bc0ba327c13a67 GIT binary patch literal 1566 zcmV+(2I2XMP)rZGih zXw&#$)jrm=iAGIK8xtz&C7L#UsP>_)mll=wMNO+ffoiD_T1#yUim(D(ys%vMfQPei zrVqOZR|L*1ZtO$(Kh4bfZvQzm-^@2KjcNS9p~TbJ{=+BFgR;y*?EJRZOY-C8(-tp7 zVORza@KQWI#+kt5$25We8u2D@-cmyFb37f!H4B+o`PybN-uT(0hvM!pG2RAaMai~Z zb8H5+fL|F7l^*}>gRWTg<2NIR8$39)H7FE$0)fri3@0JG9e^ZV$1ylSfBMXW2&%E$ zPO&yWxOMB+q<~{)6;Ked;unf2IeFmyUmqWV%KAJEV+T+Q%#hR?1dbK`*5J(O?<*bi zO;Z%!IDVk)sEnbh6R5b5f)d(`!dpynDcXcVZikO&eb-4ajOeKPP8=vpld&G6#BUZr!wEAw+((0R3 zrXbzLH_tucuqlj0hL$qu+9ey79D&OEyhyeIpghm3SOpJZ0ylh<6M!&@vIX9#5%D$^ zHQ6$u$q@+W`9uhB*iAW^QhKevc3RtRO1aoFFEin3XYxR#>%x|>M@G*&ki!ig!iN+9 z<#}G0?8a$r^U>1QCMBx?`|`Zb`y*l_6*ZQ>*_wbuTSMf8&2iX+vZ=DKzn?&FFTtQn zcOW38Q<&~zjy+M0be$yF)>!FS6Hq8Jo3G6BI3^Q~Myv1s(rIb4-UlX1veWFN9dY0H zM6f0xl*MMVIK!PJ8_3nan@8J?SO1b#qd3!TkLoU-P%r|SKQP~H&P}mTCOL|}{(ipr z>d0vS%cB+Cx!WzJJ2&|OAM+=YGa>N@@R-ePyWG|3Y)vhL_wLbMu#!7PtICQ=hz{kT!_!z`=nUlJl03sr&j0}&?P-3E-D?`>v1Tssg-)!E}hoy|JDk@}lRu&l- zYRIfV%j~QyRj3EpMT1a)jt8Ss%SYLw_Cy$ zv}^iU-;=_cfKaZ0SOQSht?Gs8E~%aDal2W+_GKB-2XL;tKLmucox&9>d6`XIZ8j@! z_e$Lm9|hmt>bvj55SBaNntrAr?+kNN?GIAf(_O<-+) z5IAObcQpIe7!!pQ3<2AlI-_PsIm(6=ma`>W50nETfTn>V*P-_A5exa4aj@g=$hAS; zoP8Zd*(akXM__&7H4yvF?#}Ce>f^YS>UvamU;ih1=wsFuSY{xIr6LQ8JwOA1AxJ1~ z^l9-RQP-pLYNJmx>tf&nGX~z3)sL;HKUp^iAua-QAzWIPE%35s-uOlRWH1CA?7VC2 zZtlWBm=oEKVJu<83hC#?DLkvxEdp_h2nm2Zr(G@2&2bfG$kht9Ju2IqI@PE(573Um z8a5O*#uCodUgj!lva#8|1C~Y)XWJ9ib=hh5;!L+aCpigk)WcS%7NR;3)K7Nx>QSlE zjN%tYjFMPp{?P~koIaf#emxNH08UH!@u4HcM>q%HlYK@Ri${Olt*FTk7vN$e@QR9l#uqzNePq-K{A831lR^T#FgJGPOIi#jBjcHipUslrouSl-W Q%m4rY07*qoM6N<$g48qYF8}}l literal 0 HcmV?d00001 diff --git a/apps/stlap/img/pause.png b/apps/stlap/img/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..ad31dadcff3ecffba6c7e015a4b2ecdcccc15b0f GIT binary patch literal 2891 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x}o+U~I{Bb`J1#c2+1T%1_J8No8Qr zm{>c}*5j~)%+dJZrAngg+8q`tEBwU%ILU0~a$O;i)fy)2qxZK-jn}iQd+~#)f)B|X zUp;uVW_9yw1&+D~3oA>_T^^nPy}5LgY%Ja#-(B6mySyPl-}vk+31*YKX2G31W}IBt zwJ@CJV!yyKLuKRBGbS%lsX2b#mZ@fM_eY)o#r1u1rs;+X3PR_N4sYo+?^tf0+x*$C zuthX=>W?`USC()K*%!rr{Lx!{Ftst=?MzA5JPRisv0D+D$zdj@k2D{xSoLy>eu_<) zWq#qcQ=!-PsMjZ2EMKovJolM^P{a`-m5zV_SI*QM9T!(kPEvIJT`2#5!RzTKmQGmB z;?~C+vcR$I?}PdeyQ8)3Eg!13K6ZHC{kVpQd135=z~VXYlaFW4VK|unz$^c!c4@-1 z$zP(pyX6@7-ac@&)I0cF!)e)s2PY@^-kjQG(pn=|VZS*46jSYXhwrnlM;FU4=XaR3 z%j+Hkd;0;8#!c62@7=w6@Am%mS%3dB99mg)Jm;_40${YTC3(BM0BIoj>AbrhNO2Z; zL>4nJ=qZCRW5rVYGN2%PiKnkC`!i-yb}Jpb3EHthA;}Wgh!W@g+}zZ>5(ej@)Wnk1 z6ovB4k_-iRPv3y>Mm}+%S<0R+jv*erj1rvBzcKy?0-#2mfDs6AN&+Pa>1V>HnHqAV z77z@@(I6TPB7z}6P{C*_8Vw?XAwW>UXet^FB7z}6Pyx+TQT{Ft9Zp`Z43JAaUHx3v IIVCg!009H(%m4rY literal 0 HcmV?d00001 diff --git a/apps/stlap/img/play.png b/apps/stlap/img/play.png new file mode 100644 index 0000000000000000000000000000000000000000..6c20c24c54d72382a69d5aa3685e3ad8fa6174ba GIT binary patch literal 2891 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x}o+U~I{Bb`J1#c2+1T%1_J8No8Qr zm{>c}*5j~)%+dJZrAngg+8q`tEBwU%ILU0~a$O;i)fy)2qxZK-jn}iQd+~#)f)B|X zUp;uVW_9yw1&+D~3oA>_T^^nPy}5LgY%Ja#-(B6mySyPl-}vk+31*YKX2G31W}IBt zwJ@CJV!yyKLuKRBGbS%lsX2b#mZ@fM_eY)o#r1u1rs;+X3PR_N4sYo+?^tf0+x*$C zuthX=>W?`USC()K*%!rr{Lx!{Ftst=?MzA5JPRisv0D+D$zdj@k2D{xSoLy>eu_<) zWq#qcQ=!-PsMjZ2EMKovJolM^P{a`-m5zV_SI*QM9T!(kPEvIJT`2#5!RzTKmQGmB z;?~C+vcR$I?}PdeyQ8)3Eg!13K6ZHC{kVpQd135=z~VXYlaFW4VK|unz$^c!c4@-1 z$zP(pyX6@7-ac@&)I0cF!)e)s2PY@^-kjQG(pn=|VZS*46jSYXhwrnlM;FU4=XaR3 z%j+Hkd;0;8#!c62@7=w6@Am%mS%3dB99mg)Jm;_40${YTC3(BM0BIoj>AbrhNO2Z; zL>4nJ=qZCRW5rVYGN2%PiKnkC`!i-yc1y0~8~!E(g(OQ{BTAg}b8}PkN*J7rQWHy3 zQxwWGOEMJPJ$(bh8~Mb6W+{8RIEHxeGD>hh{|3|p0snyj#-=9C2r~@X0!AQ!iBn3$ z4MMg6W+*i*!fOFFEF#JRN-Sc6X(ooo7L0`Sk>mqp!-$O^vMqpFM#v(HEg)nO)hxhe z5!Ed~w}_-v1k+3m4NGw}vjFA@nppr#T`Vx0s71pJhM7k-3(yUwngzHFrq}{P2E!~M zE0T#d9ApVeaX^Z}FdqmdKI;Vst0LE7sJpcdz literal 0 HcmV?d00001 diff --git a/apps/stlap/img/reset.png b/apps/stlap/img/reset.png new file mode 100644 index 0000000000000000000000000000000000000000..7a317d09795c09aabab4836c8b9ec4a6c5fe4db8 GIT binary patch literal 2891 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x}o+U~I{Bb`J1#c2+1T%1_J8No8Qr zm{>c}*5j~)%+dJZrAngg+8q`tEBwU%ILU0~a$O;i)fy)2qxZK-jn}iQd+~#)f)B|X zUp;uVW_9yw1&+D~3oA>_T^^nPy}5LgY%Ja#-(B6mySyPl-}vk+31*YKX2G31W}IBt zwJ@CJV!yyKLuKRBGbS%lsX2b#mZ@fM_eY)o#r1u1rs;+X3PR_N4sYo+?^tf0+x*$C zuthX=>W?`USC()K*%!rr{Lx!{Ftst=?MzA5JPRisv0D+D$zdj@k2D{xSoLy>eu_<) zWq#qcQ=!-PsMjZ2EMKovJolM^P{a`-m5zV_SI*QM9T!(kPEvIJT`2#5!RzTKmQGmB z;?~C+vcR$I?}PdeyQ8)3Eg!13K6ZHC{kVpQd135=z~VXYlaFW4VK|unz$^c!c4@-1 z$zP(pyX6@7-ac@&)I0cF!)e)s2PY@^-kjQG(pn=|VZS*46jSYXhwrnlM;FU4=XaR3 z%j+Hkd;0;8#!c62@7=w6@Am%mS%3dB99mg)Jm;_40${YTC3(BM0BIoj>AbrhNO2Z; zL>4nJ=qZCRW5rVYGN2%PiKnkC`!i-y4rWEypL5fJLXst}5hc#~xw)x%B@E6*sfi`2 zDGKG8B^e6tp1uL$jeO!jvy?qu978;K86`NMe`EX)1VD{A0V5FLlmto;($9oXGe{1f z0r=!#<`T33mnFm)4$@1M1?ZL#YdAG9F5Ihr6 z+Y*@Ba0@^#qn0Hw!$D@ESU?R+kPQc!NApyK;scrn5w#2l1q%qkf(q;dY8wu*0%FN% zSp*9WoHWgoDM=Q9QU(a%bS@SNqAfr+7@3X5OcWuaEWl lapTimes[slowestIndex]) slowestIndex = i; + } + + let lapMenu = { + '': { + 'title': fileNameToDateString(fileName), + 'back': () => { E.showMenu(mainMenu); } + }, + }; + lapMenu[`Total time: ${msToHumanReadable(fileData[fileData.length - 1])}`] = () => { }; + lapMenu[`Fastest lap: ${fastestIndex + 1}: ${msToHumanReadable(lapTimes[fastestIndex])}`] = () => { }; + lapMenu[`Slowest lap: ${slowestIndex + 1}: ${msToHumanReadable(lapTimes[slowestIndex])}`] = () => { }; + lapMenu[`Average lap: ${msToHumanReadable(fileData[fileData.length - 1] / fileData.length)}`] = () => { }; + + for (let i = 0; i < lapTimes.length; i++) { + lapMenu[`Lap ${i + 1}: ${msToHumanReadable(lapTimes[i])}`] = () => { }; + } + + lapMenu.Delete = () => { + E.showMenu({ + '': { + 'title': 'Are you sure?', + 'back': () => { E.showMenu(lapMenu); } + }, + 'Yes': () => { + storage.erase(fileName); + showMainMenu(); + }, + 'No': () => { E.showMenu(lapMenu); } + }); + }; + + E.showMenu(lapMenu); +} + +function showMainMenu() { + let LAP_FILES = storage.list(/stlap-[0-9]*\.json/); + LAP_FILES.sort(); + LAP_FILES.reverse(); + + let mainMenu = { + '': { + 'title': 'Sessions' + } + }; + + //I know eval is evil, but I can't think of any other way to do this. + for (let lapFile of LAP_FILES) { + mainMenu[fileNameToDateString(lapFile)] = eval(`(function() { + view('${lapFile}'); + })`); + } + + if (LAP_FILES.length == 0) { + mainMenu['No data'] = _ => { load(); }; + } + + E.showMenu(mainMenu); +} + +showMainMenu(); \ No newline at end of file diff --git a/apps/stlapview/icon.js b/apps/stlapview/icon.js new file mode 100644 index 000000000..32281b7ab --- /dev/null +++ b/apps/stlapview/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4UA///vvvvEF/muH+cDHgPABf4AElWoKhILClALH1WqAQIWHBYIABwAKEgQKD1WgBYkK1X1r4XHlWtqtVvQLG1XVBYNXHYsC1YJBBoPqC4kKEQILCvQ7EhW1BYdeBYkqytVqwCCQwkqCgILCq4LFIoILCqoLEIwIsBGQJIBBZ+pA4Na0oDBtQLGvSFCBaYjIHYR3CI5AADBYhrCAAaDHAASDGQASGCBYizCAASzFZYQACZYrjCIwb7QHgIkCvQ6EGAWq+tf1QuEGAWqAAQuFEgQKBEQw9DHIwAuA=")) diff --git a/apps/stlapview/icon.png b/apps/stlapview/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..92ffe73b7f172f7019486231d5bc0ba327c13a67 GIT binary patch literal 1566 zcmV+(2I2XMP)rZGih zXw&#$)jrm=iAGIK8xtz&C7L#UsP>_)mll=wMNO+ffoiD_T1#yUim(D(ys%vMfQPei zrVqOZR|L*1ZtO$(Kh4bfZvQzm-^@2KjcNS9p~TbJ{=+BFgR;y*?EJRZOY-C8(-tp7 zVORza@KQWI#+kt5$25We8u2D@-cmyFb37f!H4B+o`PybN-uT(0hvM!pG2RAaMai~Z zb8H5+fL|F7l^*}>gRWTg<2NIR8$39)H7FE$0)fri3@0JG9e^ZV$1ylSfBMXW2&%E$ zPO&yWxOMB+q<~{)6;Ked;unf2IeFmyUmqWV%KAJEV+T+Q%#hR?1dbK`*5J(O?<*bi zO;Z%!IDVk)sEnbh6R5b5f)d(`!dpynDcXcVZikO&eb-4ajOeKPP8=vpld&G6#BUZr!wEAw+((0R3 zrXbzLH_tucuqlj0hL$qu+9ey79D&OEyhyeIpghm3SOpJZ0ylh<6M!&@vIX9#5%D$^ zHQ6$u$q@+W`9uhB*iAW^QhKevc3RtRO1aoFFEin3XYxR#>%x|>M@G*&ki!ig!iN+9 z<#}G0?8a$r^U>1QCMBx?`|`Zb`y*l_6*ZQ>*_wbuTSMf8&2iX+vZ=DKzn?&FFTtQn zcOW38Q<&~zjy+M0be$yF)>!FS6Hq8Jo3G6BI3^Q~Myv1s(rIb4-UlX1veWFN9dY0H zM6f0xl*MMVIK!PJ8_3nan@8J?SO1b#qd3!TkLoU-P%r|SKQP~H&P}mTCOL|}{(ipr z>d0vS%cB+Cx!WzJJ2&|OAM+=YGa>N@@R-ePyWG|3Y)vhL_wLbMu#!7PtICQ=hz{kT!_!z`=nUlJl03sr&j0}&?P-3E-D?`>v1Tssg-)!E}hoy|JDk@}lRu&l- zYRIfV%j~QyRj3EpMT1a)jt8Ss%SYLw_Cy$ zv}^iU-;=_cfKaZ0SOQSht?Gs8E~%aDal2W+_GKB-2XL;tKLmucox&9>d6`XIZ8j@! z_e$Lm9|hmt>bvj55SBaNntrAr?+kNN?GIAf(_O<-+) z5IAObcQpIe7!!pQ3<2AlI-_PsIm(6=ma`>W50nETfTn>V*P-_A5exa4aj@g=$hAS; zoP8Zd*(akXM__&7H4yvF?#}Ce>f^YS>UvamU;ih1=wsFuSY{xIr6LQ8JwOA1AxJ1~ z^l9-RQP-pLYNJmx>tf&nGX~z3)sL;HKUp^iAua-QAzWIPE%35s-uOlRWH1CA?7VC2 zZtlWBm=oEKVJu<83hC#?DLkvxEdp_h2nm2Zr(G@2&2bfG$kht9Ju2IqI@PE(573Um z8a5O*#uCodUgj!lva#8|1C~Y)XWJ9ib=hh5;!L+aCpigk)WcS%7NR;3)K7Nx>QSlE zjN%tYjFMPp{?P~koIaf#emxNH08UH!@u4HcM>q%HlYK@Ri${Olt*FTk7vN$e@QR9l#uqzNePq-K{A831lR^T#FgJGPOIi#jBjcHipUslrouSl-W Q%m4rY07*qoM6N<$g48qYF8}}l literal 0 HcmV?d00001 diff --git a/apps/stlapview/metadata.json b/apps/stlapview/metadata.json new file mode 100644 index 000000000..aa54a7b67 --- /dev/null +++ b/apps/stlapview/metadata.json @@ -0,0 +1,27 @@ +{ + "id": "stlapview", + "name": "Stopwatch laps", + "version": "0.02", + "description": "Optional lap viewer for my stopwatch app", + "icon": "icon.png", + "type": "app", + "tags": "tools,app", + "supports": [ + "BANGLEJS2" + ], + "allow_emulator": true, + "storage": [ + { + "name": "stlapview.app.js", + "url": "app.js" + }, + { + "name": "stlapview.img", + "url": "icon.js", + "evaluate": true + } + ], + "dependencies": { + "stlap": "app" + } +} \ No newline at end of file From 5dbf7205b01f52aa320c5fb0aaaba721c8f8658d Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Thu, 3 Nov 2022 18:08:16 +0100 Subject: [PATCH 060/179] Exit with short press of BTN1 --- apps/calculator/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/calculator/app.js b/apps/calculator/app.js index 40953254e..c93b36e43 100644 --- a/apps/calculator/app.js +++ b/apps/calculator/app.js @@ -402,6 +402,7 @@ if (process.env.HWVERSION==1) { swipeEnabled = false; drawGlobal(); } else { // touchscreen? + setWatch(load, BTN1, {edge:"falling"}); // Exit with a short press to physical button selected = "NONE"; swipeEnabled = true; prepareScreen(numbers, numbersGrid, COLORS.DEFAULT); @@ -440,5 +441,4 @@ if (process.env.HWVERSION==1) { }); } - displayOutput(0); From 71d59896b1f3dffe6a88b6f9d3250532774ef976 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Thu, 3 Nov 2022 18:09:14 +0100 Subject: [PATCH 061/179] Update ChangeLog --- apps/calculator/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/calculator/ChangeLog b/apps/calculator/ChangeLog index a08a0f5a7..f3ce3a928 100644 --- a/apps/calculator/ChangeLog +++ b/apps/calculator/ChangeLog @@ -3,3 +3,4 @@ 0.03: Support for different screen sizes and touchscreen 0.04: Display current operation on LHS 0.05: Grid positioning and swipe controls to switch between numbers, operators and special (for Bangle.js 2) +0.06: Bangle.js 2: Exit with a short press of the physical button From 1b73fadcb812ea381e87755cb2eecf894e2b9699 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Thu, 3 Nov 2022 18:09:32 +0100 Subject: [PATCH 062/179] Update metadata.json --- apps/calculator/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/calculator/metadata.json b/apps/calculator/metadata.json index e78e4d54f..536a6955e 100644 --- a/apps/calculator/metadata.json +++ b/apps/calculator/metadata.json @@ -2,7 +2,7 @@ "id": "calculator", "name": "Calculator", "shortName": "Calculator", - "version": "0.05", + "version": "0.06", "description": "Basic calculator reminiscent of MacOs's one. Handy for small calculus.", "icon": "calculator.png", "screenshots": [{"url":"screenshot_calculator.png"}], From ba543b53d92f392d01746ced804470047c108904 Mon Sep 17 00:00:00 2001 From: Simon Weis Date: Thu, 3 Nov 2022 17:40:39 +0000 Subject: [PATCH 063/179] Create Enton clock based on Anton clock --- apps/enton_clock/ChangeLog | 1 + apps/enton_clock/README.md | 9 + apps/enton_clock/app-icon.js | 1 + apps/enton_clock/app.js | 67 + apps/enton_clock/app.png | Bin 0 -> 905 bytes apps/enton_clock/metadata.json | 17 + apps/enton_clock/screenshot.png | Bin 0 -> 2081 bytes package-lock.json | 2928 +------------------------------ 8 files changed, 106 insertions(+), 2917 deletions(-) create mode 100644 apps/enton_clock/ChangeLog create mode 100644 apps/enton_clock/README.md create mode 100644 apps/enton_clock/app-icon.js create mode 100644 apps/enton_clock/app.js create mode 100644 apps/enton_clock/app.png create mode 100644 apps/enton_clock/metadata.json create mode 100644 apps/enton_clock/screenshot.png diff --git a/apps/enton_clock/ChangeLog b/apps/enton_clock/ChangeLog new file mode 100644 index 000000000..62e2d0c20 --- /dev/null +++ b/apps/enton_clock/ChangeLog @@ -0,0 +1 @@ +0.1: New App! \ No newline at end of file diff --git a/apps/enton_clock/README.md b/apps/enton_clock/README.md new file mode 100644 index 000000000..8c788c7a5 --- /dev/null +++ b/apps/enton_clock/README.md @@ -0,0 +1,9 @@ +Enton - Enhanced Anton Clock + +This clock face is based on the 'Anton Clock'. + +Things I changed: + +- The main font for the time is now Audiowide +- Removed the written out day name and replaced it with steps and bpm +- Changed the date string to a (for me) more readable string \ No newline at end of file diff --git a/apps/enton_clock/app-icon.js b/apps/enton_clock/app-icon.js new file mode 100644 index 000000000..9993b0871 --- /dev/null +++ b/apps/enton_clock/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkE/4A/AH4A/AH4A/AH4Aw+cikf/mQDCAAIFBAwQDBBYgXCgEDAQIABn4JBkAFBgIKDgQwFmMD+UCmcgl/zEIMzmcQmYKBmYiCAAfxC4QrBl8wBwcgkYsGC4sAiMAF4UxiIGBn8QAgMSC48wgMRiEDBAISCiYcFC48v//yC4PzgJAGiAXIiczPgPzC4JyBmf/AYQXI+KcCj8wmYFCgEjAYQ3G+cjbQIABJIMzAoUin7XIADpSEK4rWGI4MhmRJBn8j+U/d4MimUTkUzIw5dBl4UBMgIXBAgMyLYKOBmQXHiSbCDgMyl8z+UjmJ1BHgJbHCgM/IYQABAgQJBYYYA/AH4AtaQU/mTvBBozWBd44KBkUSkLnBEo8jkcvBI0/CgMiDAIXHHYIXImUzJQJHH+Y+Bn6Z/ABQA==")) \ No newline at end of file diff --git a/apps/enton_clock/app.js b/apps/enton_clock/app.js new file mode 100644 index 000000000..69fdea479 --- /dev/null +++ b/apps/enton_clock/app.js @@ -0,0 +1,67 @@ +Graphics.prototype.setFontAudiowide = function() { + // Actual height 33 (36 - 4) + var widths = atob("CiAsESQjJSQkHyQkDA=="); + var font = atob("AAAAAAAAAAAAAAAAAAAAAPAAAAAAAfgAAAAAAfgAAAAAAfgAAAAAAfgAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAADgAAAAAAHgAAAAAAfgAAAAAA/gAAAAAD/gAAAAAH/gAAAAAf/AAAAAB/8AAAAAD/4AAAAAP/gAAAAAf/AAAAAB/8AAAAAD/4AAAAAP/gAAAAAf+AAAAAB/8AAAAAH/wAAAAAP/gAAAAA/+AAAAAB/8AAAAAD/wAAAAAD/gAAAAAD+AAAAAAD4AAAAAADwAAAAAADAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAA//+AAAAB///AAAAH///wAAAP///4AAAf///8AAA////+AAA/4AP+AAB/gAD/AAB/AA9/AAD+AB+/gAD+AD+/gAD+AD+/gAD8AH+fgAD8AP8fgAD8AP4fgAD8Af4fgAD8A/wfgAD8A/gfgAD8B/gfgAD8D/AfgAD8D+AfgAD8H+AfgAD8P8AfgAD8P4AfgAD8f4AfgAD8/wAfgAD8/gAfgAD+/gA/gAD+/AA/gAB/eAB/AAB/sAD/AAB/wAH/AAA////+AAAf///8AAAP///4AAAH///wAAAD///gAAAA//+AAAAAP/4AAAAAAAAAAAAAAAAAAAAAAAAAAAD8AAAAAAD8AAAAAAD8AAAAAAD8AAAAAAD8AAAAAAD8AAAAAAD/////gAD/////gAD/////gAD/////gAD/////gAD/////gAD/////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//gAAAAH//gAAAAP//gAD8Af//gAD8A///gAD8B///gAD8B///gAD8B/AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD+D+AfgAD//+AfgAD//+AfgAB//8AfgAA//4AfgAAf/wAfgAAP/gAfgAAB8AAfgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD+B+A/gAD/////gAB/////AAB/////AAA////+AAAf///8AAAP///4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//4AAAAD//8AAAAD//+AAAAD//+AAAAD//+AAAAD//+AAAAD//+AAAAAAB+AAAAAAB+AAAAAAB+AAAAAAB+AAAAAAB+AAAAAAB+AAAAAAB+AAAAAAB+AAAAAAB+AAAAAAB+AAAAAAB+AAAAAAB+AAAAAAB+AAAAAAB+AAAAAAB+AAAAAAB+AAAAAAB+AAAAAAB+AAAAD/////gAD/////gAD/////gAD/////gAD/////gAD/////gAD/////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//AAfgAD//wAfgAD//4AfgAD//8AfgAD//8AfgAD//+AfgAD8D+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B/A/gAD8B///gAD8B///gAD8A///AAD8A///AAAAAf/+AAAAAP/4AAAAAD/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB///AAAAH///wAAAf///8AAAf///8AAA////+AAB/////AAB/h+H/AAD/B+B/gAD+B+A/gAD+B+A/gAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B/A/gAD8B///gAD8B///gAD8A///AAAAAf//AAAAAf/+AAAAAH/4AAAAAB/gAAAAAAAAAAAAAAAAAAAAAAAAAAD8AAAAAAD8AAAAAAD8AAAAAAD8AAAAAAD8AAAAgAD8AAABgAD8AAAHgAD8AAAfgAD8AAA/gAD8AAD/gAD8AAP/gAD8AA//gAD8AB//AAD8AH/8AAD8Af/wAAD8A//AAAD8D/+AAAD8P/4AAAD8f/gAAAD9//AAAAD//8AAAAD//wAAAAD//gAAAAD/+AAAAAD/4AAAAAD/wAAAAAD/AAAAAAD8AAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gAAAAAH/4AAAAAP/8AAAH+f/+AAAf////AAA/////gAB/////gAB///A/gAD//+AfgAD//+AfgAD+D+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD+D+AfgAD//+AfgAD//+AfgAB///A/gAB/////gAA/////AAAP////AAAD+f/+AAAAAP/8AAAAAH/4AAAAAA+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/AAAAAAf/wAAAAA//4AAAAB//8AAAAB//8AfgAD//+AfgAD/D+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD8B+AfgAD+B+A/gAD+B+A/gAD/B+B/gAB/////AAB/////AAA////+AAAf///8AAAP///4AAAH///wAAAB///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAPAAAA/AAfgAAA/AAfgAAA/AAfgAAA/AAfgAAAeAAPAAAAAAAAAAAAAAAAAAAAAAAAAA"); + var scale = 1; // size multiplier for this font + g.setFontCustom(font, 46, widths, 48+(scale<<8)+(1<<16)); +}; + +function getSteps() { + var steps = 0; + try{ + if (WIDGETS.wpedom !== undefined) { + steps = WIDGETS.wpedom.getSteps(); + } else if (WIDGETS.activepedom !== undefined) { + steps = WIDGETS.activepedom.getSteps(); + } else { + steps = Bangle.getHealthStatus("day").steps; + } + } catch(ex) { + // In case we failed, we can only show 0 steps. + return "?"; + } + + return Math.round(steps); +} + +{ // must be inside our own scope here so that when we are unloaded everything disappears + // we also define functions using 'let fn = function() {..}' for the same reason. function decls are global +let drawTimeout; + + +// Actually draw the watch face +let draw = function() { + var x = g.getWidth() / 2; + var y = g.getHeight() / 2; + g.reset().clearRect(Bangle.appRect); // clear whole background (w/o widgets) + var date = new Date(); + var timeStr = require("locale").time(date, 1); // Hour and minute + g.setFontAlign(0, 0).setFont("Audiowide").drawString(timeStr, x, y); + var dateStr = require("locale").date(date, 1).toUpperCase(); + g.setFontAlign(0, 0).setFont("6x8", 2).drawString(dateStr, x, y+28); + g.setFontAlign(0, 0).setFont("6x8", 2); + g.drawString(getSteps(), 50, y+70); + g.drawString(Math.round(Bangle.getHealthStatus("last").bpm), g.getWidth() -37, y + 70); + + // queue next draw + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); +}; + +// Show launcher when middle button pressed +Bangle.setUI({ + mode : "clock", + remove : function() { + // Called to unload all of the clock app + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + delete Graphics.prototype.setFontAnton; + }}); +// Load widgets +Bangle.loadWidgets(); +draw(); +setTimeout(Bangle.drawWidgets,0); +} diff --git a/apps/enton_clock/app.png b/apps/enton_clock/app.png new file mode 100644 index 0000000000000000000000000000000000000000..5b634de5a727c06f2c0d679d2853754d3f04469a GIT binary patch literal 905 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZANS%G|}ByV>Y zhX3vTXZ8bm>?NMQuI$ganFZx#Z;7NI017eY7x{%So?lcx3#fR5r;B5V$MLt5y?ulO zMcUST%;?B0WY_C>m+<<~(u*@Bk|JNUu{v@}g{yQpa4r?dHQ?2CUdY=lxM+e#|FmTa zTLTt2Eley3SZou0%K4tesnrn+E@eKqINW3)EbQE&{nPxpz54glJD)#^V>vEj#p>4> z{9wrek+>i$UY^d?S1nG;OkoSn3Y(=Fq4m5c%CtgcgNxD?E?Yy6!xxrLY@Vbhb9e(s zN$u1lha%crv-_B&m$1xqY%|i(Vis+@zKzZMuZm~go_;A!ow-T5|Ap$?+I0dNKFpPs zIeAd+67!piy>at-LIVYj4?54PAYun|?a&u}}x>$Ga};@8!WV`O%fZtG@WqO|!rn^5ObrIO;!-xuxVZSAz2 zt8RC^Ah2a!?gxhE5}7-#mO+_*A7##Hsl`<84D!2K`}t?gnM$jgOWU`6Vm5o8@!|XL z^6!cpxHp(?_+Be5X8T}fdRf{Zr-YEXw_-o9VfQ#3)!4nxgwdq@wpO;ChP*|Vwv~@d zvIB!e*XQ`N;nIJOoZ8OxyeLw5P1p~&S*t@U*6n-l%YF6Bujvdgybk%EZDVT}yyL%W z+36JSWp-{;?*>ed3Hu%KaKh8Att<`)3?2GQ*KJ?daQcqr#k`-lJ_)m}-5dQ)e_mhT zLpyEJKcCsTWUPMWM_YZ1`tN)oe*Nk~;bXnO#OLYVIcxuD%>|wtapyiYKKNAaw0dXw zD(~Q|O(Hc1o?qIlx+bcvUbX!2HmA6t8SAvGmgw?-Y)IhVntx&vH^Xs@376Ei&zW)2 zPX1Z>4bw{r;k=w}&;C^_a2#YX_Za4FaWx;r$?u{kC%uh_RgD|2>gTR#y*X&SQ25 z)b8vIj79vb_k3KDQ%u;cQN<8uSt~0>{Kdp4rB$xp|A&J^kje-Qz~UFNP*@=B3IIQ> z@Oka%_SI>#lkszFNP95t$9Lckh1o(_8l{eQQtgzL3hBr2P)cs0zJYPyHa1kkPVbQp_Z4L@z_w-r>4()V}acM1kRHm zl|}a}D0k+n7dY_+7N=QOt{H+n+)8$`z=p*1UT#(}-%!6-y9KB~a!q&bU20HqY})=A z$)eCsg~SBc?<^4A(Q>d>W2MAZb1knTu2t_SEs}8uv@&sOM#m%;)soTM9~!OmsQbx| z7o$3)uXra~o%eEVw}g$)2Ai+7x?WGv**j{c>8t(+7|`nu`h}0P(Wdkta?IE60gq89 zAIx3ZIG*1AxCiaOMCiT(INX?8h%-Ni6W&_5_G_89@bp(S^DgEx|OadlqU z8AWu6xa>LE8sz^%B8*iisaPrVZ8-&h839T`+9w@3ubSy{(1)x_`H#%|a(e4*uckux zyr8@#%gb>opGYjQUOGa^Tz0u!wai(^Ed_ay#*b<|`xxJHW8^K8#J&jyhb_9W&+jdx zWE>>1sDY1&Uid`y>hW?(u8ppY zYRK+e6fO$yZFcT#LdLr-^zzo_H(m;UDEnUF+xDTud?SjUR%?@)u^k}l37PtC)Z~Tb z19pnP&+eAx-Fz1vRY7VCnQnVCIcqn(NqN)%nnQgO#&VJ*Tz5`n^L7MVX`8u|jis38 zE!H8)6()PS0?7-%WRf|3RvGcvA^0^x=Mj75?eK7P{y`1jWbSF@LOE>BE%xJF&ckkW z_X^9D~C8Q9*)8pesZr@)&EJc@TO0oFw5lZ#4#p8$-gzlZA-@ z-Y0yit$TJISx7S1@bKHSbWPU4D(hIzx!|1X@Ov@;mhmeacQXi>N`qN;J&Tu42`({2 zVuYCIoec97g)DV_NZ$9*GDbzr$9^HhN} z`Lk9p-}pQ_k6$ zc^yy^`#gu%hb6bmPpvnyi0-FUVx1AbYedjYh1bSRqTL zJ000r4;yFUEN{LgiC?LOk*ytE)8TKKv@v;k9Gd%*+MjvGBxOyDL-#jLtHr#Z;@XU| zFD9B;b7-BJSqOpmh7^b)B@?;x+AKy@jCfv5uXl?f%zUGgdy99P4= zBwr|#M96Ywfm#Zd4r7lFKchQ;hs`t&RCP)q;8v7}8LSieHzhdnHFySqR}spi)i6_@ zotIhC-jk{`4?kXY&J(KNGu_G|0A=uLq@j9K@csEr18U`{m!k&Mus2b?PI*G6XPq=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, - "dependencies": { - "defer-to-connect": "^1.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "dependencies": { - "string-width": "^4.1.0" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-includes": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", - "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", - "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, - "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cacheable-request/node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dev": true, - "dependencies": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, - "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dev": true, - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/es-abstract": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.17.0.tgz", - "integrity": "sha512-gq0m0BTJfci60Fz4nczYxNAlED+sMcihltndR8t9t1evnU/azx53x3t2UHXC/uRjcbvRw/XctpaNygSTcQD+Iw==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.2", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-airbnb-base": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", - "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", - "dev": true, - "dependencies": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.2" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "find-up": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", - "has": "^1.0.3", - "is-core-module": "^2.8.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/espree": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", - "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", - "dev": true, - "dependencies": { - "acorn": "^8.7.1", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/espree/node_modules/acorn": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dev": true, - "dependencies": { - "ini": "2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globals": { - "version": "13.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", - "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "dependencies": { - "ci-info": "^2.0.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.0" - } - }, - "node_modules/latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dev": true, - "dependencies": { - "package-json": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/nodemon": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.16.tgz", - "integrity": "sha512-zsrcaOfTWRuUzBn3P44RDliLlp263Z/76FPoHFr3cFFkOz0lTPAcIw8dCzfdVIx/t3AtDYCZRCDkoCojJqaG3w==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5", - "update-notifier": "^5.1.0" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/nodemon/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/nodemon/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/nodemon/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm-watch": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/npm-watch/-/npm-watch-0.11.0.tgz", - "integrity": "sha512-wAOd0moNX2kSA2FNvt8+7ORwYaJpQ1ZoWjUYdb1bBCxq4nkWuU0IiJa9VpVxrj5Ks+FGXQd62OC/Bjk0aSr+dg==", - "dev": true, - "dependencies": { - "nodemon": "^2.0.7", - "through2": "^4.0.2" - }, - "bin": { - "npm-watch": "cli.js" - } - }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", - "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "dev": true, - "dependencies": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dev": true, - "dependencies": { - "escape-goat": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "dev": true, - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dev": true, - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", - "dev": true, - "dependencies": { - "lowercase-keys": "^1.0.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "dependencies": { - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", - "dev": true, - "dependencies": { - "readable-stream": "3" - } - }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "dependencies": { - "nopt": "~1.0.10" - }, - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", - "dev": true, - "dependencies": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/yeoman/update-notifier?sponsor=1" - } - }, - "node_modules/update-notifier/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", - "dev": true, - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - }, "dependencies": { "@eslint/eslintrc": { "version": "1.3.0", @@ -2979,8 +74,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "ajv": { "version": "6.12.6", @@ -4749,15 +1843,6 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } - }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -4791,6 +1876,15 @@ "es-abstract": "^1.19.5" } }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", From 1a2c2c552a2d3290d21cf1b5dec1181c01a59ddf Mon Sep 17 00:00:00 2001 From: Simon Weis Date: Thu, 3 Nov 2022 17:51:49 +0000 Subject: [PATCH 064/179] Fix entonclk id --- apps/{enton_clock => entonclk}/ChangeLog | 0 apps/{enton_clock => entonclk}/README.md | 0 apps/{enton_clock => entonclk}/app-icon.js | 0 apps/{enton_clock => entonclk}/app.js | 0 apps/{enton_clock => entonclk}/app.png | Bin apps/{enton_clock => entonclk}/metadata.json | 0 apps/{enton_clock => entonclk}/screenshot.png | Bin 7 files changed, 0 insertions(+), 0 deletions(-) rename apps/{enton_clock => entonclk}/ChangeLog (100%) rename apps/{enton_clock => entonclk}/README.md (100%) rename apps/{enton_clock => entonclk}/app-icon.js (100%) rename apps/{enton_clock => entonclk}/app.js (100%) rename apps/{enton_clock => entonclk}/app.png (100%) rename apps/{enton_clock => entonclk}/metadata.json (100%) rename apps/{enton_clock => entonclk}/screenshot.png (100%) diff --git a/apps/enton_clock/ChangeLog b/apps/entonclk/ChangeLog similarity index 100% rename from apps/enton_clock/ChangeLog rename to apps/entonclk/ChangeLog diff --git a/apps/enton_clock/README.md b/apps/entonclk/README.md similarity index 100% rename from apps/enton_clock/README.md rename to apps/entonclk/README.md diff --git a/apps/enton_clock/app-icon.js b/apps/entonclk/app-icon.js similarity index 100% rename from apps/enton_clock/app-icon.js rename to apps/entonclk/app-icon.js diff --git a/apps/enton_clock/app.js b/apps/entonclk/app.js similarity index 100% rename from apps/enton_clock/app.js rename to apps/entonclk/app.js diff --git a/apps/enton_clock/app.png b/apps/entonclk/app.png similarity index 100% rename from apps/enton_clock/app.png rename to apps/entonclk/app.png diff --git a/apps/enton_clock/metadata.json b/apps/entonclk/metadata.json similarity index 100% rename from apps/enton_clock/metadata.json rename to apps/entonclk/metadata.json diff --git a/apps/enton_clock/screenshot.png b/apps/entonclk/screenshot.png similarity index 100% rename from apps/enton_clock/screenshot.png rename to apps/entonclk/screenshot.png From e57543bd48046d115c442cce718b695659817d9d Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Thu, 3 Nov 2022 18:53:32 +0100 Subject: [PATCH 065/179] Update app.js --- apps/calculator/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/calculator/app.js b/apps/calculator/app.js index c93b36e43..3a8486452 100644 --- a/apps/calculator/app.js +++ b/apps/calculator/app.js @@ -402,7 +402,7 @@ if (process.env.HWVERSION==1) { swipeEnabled = false; drawGlobal(); } else { // touchscreen? - setWatch(load, BTN1, {edge:"falling"}); // Exit with a short press to physical button + setWatch(_ => {load();}, BTN1, {edge:"falling"}); // Exit with a short press to physical button selected = "NONE"; swipeEnabled = true; prepareScreen(numbers, numbersGrid, COLORS.DEFAULT); From 6d63552f4633d88f6040c03df47789df689f9600 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Thu, 3 Nov 2022 19:15:28 +0100 Subject: [PATCH 066/179] Change to swipe events from drag --- apps/calculator/app.js | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/apps/calculator/app.js b/apps/calculator/app.js index 3a8486452..571a5b27f 100644 --- a/apps/calculator/app.js +++ b/apps/calculator/app.js @@ -402,7 +402,7 @@ if (process.env.HWVERSION==1) { swipeEnabled = false; drawGlobal(); } else { // touchscreen? - setWatch(_ => {load();}, BTN1, {edge:"falling"}); // Exit with a short press to physical button + setWatch(_ => {load();}, BTN1, {edge:'falling'}); // Exit with a short press to physical button selected = "NONE"; swipeEnabled = true; prepareScreen(numbers, numbersGrid, COLORS.DEFAULT); @@ -420,23 +420,18 @@ if (process.env.HWVERSION==1) { } } }); - var lastX = 0, lastY = 0; - Bangle.on('drag', (e) => { - if (!e.b) { - if (lastX > 50) { // right - drawSpecials(); - } else if (lastX < -50) { // left - drawOperators(); - } else if (lastY > 50) { // down - drawNumbers(); - } else if (lastY < -50) { // up - drawNumbers(); - } - lastX = 0; - lastY = 0; - } else { - lastX = lastX + e.dx; - lastY = lastY + e.dy; + Bangle.on('swipe', (LR, UD) => { + if (LR == 1) { // right + drawSpecials(); + } + if (LR == -1) { // left + drawOperators(); + } + if (UD == 1) { // down + drawNumbers(); + } + if (UD == -1) { // up + drawNumbers(); } }); } From c382bef7d9b349928033f6a3097fdbee15c8ee73 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Thu, 3 Nov 2022 21:09:18 +0100 Subject: [PATCH 067/179] gpstrek - Remove obsolete compass heading workaround --- apps/gpstrek/app.js | 2 +- apps/gpstrek/widget.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/gpstrek/app.js b/apps/gpstrek/app.js index 919f114ea..0b2168b71 100644 --- a/apps/gpstrek/app.js +++ b/apps/gpstrek/app.js @@ -683,7 +683,7 @@ const compassSliceData = { }, getCourse: function (){ if(compassSliceData.getCourseType() == "GPS") return state.currentPos.course; - return state.compassHeading?360-state.compassHeading:undefined; + return state.compassHeading?state.compassHeading:undefined; }, getPoints: function (){ let points = []; diff --git a/apps/gpstrek/widget.js b/apps/gpstrek/widget.js index 8b6b04a78..347df2df5 100644 --- a/apps/gpstrek/widget.js +++ b/apps/gpstrek/widget.js @@ -24,7 +24,7 @@ function onGPS(fix) { } function onMag(e) { - if (!state.compassHeading) state.compassHeading = 360-e.heading; + if (!state.compassHeading) state.compassHeading = e.heading; //if (a+180)mod 360 == b then //return (a+b)/2 mod 360 and ((a+b)/2 mod 360) + 180 (they are both the solution, so you may choose one depending if you prefer counterclockwise or clockwise direction) From 2becffbdf76d0bdff719ad014a60433203534cd6 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Thu, 3 Nov 2022 21:09:59 +0100 Subject: [PATCH 068/179] gpstrek - Show target marker for waypoints --- apps/gpstrek/app.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/gpstrek/app.js b/apps/gpstrek/app.js index 0b2168b71..02432175e 100644 --- a/apps/gpstrek/app.js +++ b/apps/gpstrek/app.js @@ -693,6 +693,9 @@ const compassSliceData = { if (state.currentPos && state.currentPos.lon && state.route){ points.push({bearing:bearing(state.currentPos, getLast(state.route)), color:"#00f"}); } + if (state.currentPos && state.currentPos.lon && state.waypoint){ + points.push({bearing:bearing(state.currentPos, state.waypoint), color:"#00f"}); + } return points; }, getMarkers: function (){ From 0bbec4ebfb3b960fdfc3738ee707106cda379e84 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Thu, 3 Nov 2022 21:24:51 +0100 Subject: [PATCH 069/179] gpstrek - Show flag instead of circle for target --- apps/gpstrek/README.md | 2 +- apps/gpstrek/app.js | 16 ++++++++++++---- apps/gpstrek/screen2.png | Bin 3652 -> 3840 bytes 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/gpstrek/README.md b/apps/gpstrek/README.md index 6edad2b1d..c55f5a8bf 100644 --- a/apps/gpstrek/README.md +++ b/apps/gpstrek/README.md @@ -10,7 +10,7 @@ Tapping or button to switch to the next information display, swipe right for the Choose either a route or a waypoint as basis for the display. -After this selection and availability of a GPS fix the compass will show a blue dot for your destination and a green one for possibly available waypoints on the way. +After this selection and availability of a GPS fix the compass will show a checkered flag for your destination and a green dot for possibly available waypoints on the way. Waypoints are shown with name if available and distance to waypoint. As long as no GPS signal is available the compass shows the heading from the build in magnetometer. When a GPS fix becomes available, the compass display shows the GPS course. This can be differentiated by the display of bubble levels on top and sides of the compass. diff --git a/apps/gpstrek/app.js b/apps/gpstrek/app.js index 02432175e..68be82dff 100644 --- a/apps/gpstrek/app.js +++ b/apps/gpstrek/app.js @@ -239,8 +239,14 @@ function getCompassSlice(compassDataSource){ } else { bpos=Math.round(bpos*increment); } - graphics.setColor(p.color); - graphics.fillCircle(bpos,y+height-12,Math.floor(width*0.03)); + if (p.color){ + graphics.setColor(p.color); + } + if (p.icon){ + graphics.drawImage(p.icon, bpos,y+height-12, {rotate:0,scale:2}); + } else { + graphics.fillCircle(bpos,y+height-12,Math.floor(width*0.03)); + } } } if (compassDataSource.getMarkers){ @@ -677,6 +683,8 @@ function setClosestWaypoint(route, startindex, progress){ let screen = 1; +const finishIcon = atob("CggB//meZmeZ+Z5n/w=="); + const compassSliceData = { getCourseType: function(){ return (state.currentPos && state.currentPos.course) ? "GPS" : "MAG"; @@ -691,10 +699,10 @@ const compassSliceData = { points.push({bearing:bearing(state.currentPos, state.route.currentWaypoint), color:"#0f0"}); } if (state.currentPos && state.currentPos.lon && state.route){ - points.push({bearing:bearing(state.currentPos, getLast(state.route)), color:"#00f"}); + points.push({bearing:bearing(state.currentPos, getLast(state.route)), icon: finishIcon}); } if (state.currentPos && state.currentPos.lon && state.waypoint){ - points.push({bearing:bearing(state.currentPos, state.waypoint), color:"#00f"}); + points.push({bearing:bearing(state.currentPos, state.waypoint), icon: finishIcon}); } return points; }, diff --git a/apps/gpstrek/screen2.png b/apps/gpstrek/screen2.png index 12cd659751c8d77e194ed553bb6ef142e116a33e..9a6e14e062efdc32281e927bf0ccafd4a8537a03 100644 GIT binary patch delta 3812 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 MdS=((>0rbE597Y^82|tP From 0e8b3a3397bbb01bdb7db9897c063049abae1e5a Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Thu, 3 Nov 2022 21:49:13 +0100 Subject: [PATCH 070/179] gpstrek - Bump version --- apps/gpstrek/ChangeLog | 2 ++ apps/gpstrek/metadata.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/gpstrek/ChangeLog b/apps/gpstrek/ChangeLog index b72d3fae2..d46ada767 100644 --- a/apps/gpstrek/ChangeLog +++ b/apps/gpstrek/ChangeLog @@ -6,3 +6,5 @@ 0.05: Added adjustment for Bangle.js magnetometer heading fix 0.06: Fix waypoint menu always selecting last waypoint Fix widget adding listeners more than once +0.07: Show checkered flag for target markers + Single waypoints are now shown in the compass view diff --git a/apps/gpstrek/metadata.json b/apps/gpstrek/metadata.json index 3895c025b..cf5d06baa 100644 --- a/apps/gpstrek/metadata.json +++ b/apps/gpstrek/metadata.json @@ -1,7 +1,7 @@ { "id": "gpstrek", "name": "GPS Trekking", - "version": "0.06", + "version": "0.07", "description": "Helper for tracking the status/progress during hiking. Do NOT depend on this for navigation!", "icon": "icon.png", "screenshots": [{"url":"screen1.png"},{"url":"screen2.png"},{"url":"screen3.png"},{"url":"screen4.png"}], From b13eecee0aa35d61f5b114dce7254d33b21c9517 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Fri, 4 Nov 2022 08:06:29 +0100 Subject: [PATCH 071/179] gpstrek - Correctly return to menu if selecting no in background menu --- apps/gpstrek/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/gpstrek/app.js b/apps/gpstrek/app.js index 68be82dff..f26811ed3 100644 --- a/apps/gpstrek/app.js +++ b/apps/gpstrek/app.js @@ -601,8 +601,8 @@ function showBackgroundMenu(){ "title" : "Background", back : showMenu, }, - "Start" : ()=>{ E.showPrompt("Start?").then((v)=>{ if (v) {WIDGETS.gpstrek.start(true); removeMenu();} else {E.showMenu(mainmenu);}});}, - "Stop" : ()=>{ E.showPrompt("Stop?").then((v)=>{ if (v) {WIDGETS.gpstrek.stop(true); removeMenu();} else {E.showMenu(mainmenu);}});}, + "Start" : ()=>{ E.showPrompt("Start?").then((v)=>{ if (v) {WIDGETS.gpstrek.start(true); removeMenu();} else {showMenu();}}).catch(()=>{E.showMenu(mainmenu);});}, + "Stop" : ()=>{ E.showPrompt("Stop?").then((v)=>{ if (v) {WIDGETS.gpstrek.stop(true); removeMenu();} else {showMenu();}}).catch(()=>{E.showMenu(mainmenu);});}, }; E.showMenu(menu); } From 8482576064ea98c078a05c5c54dcebb422dbc390 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Nov 2022 08:28:46 +0000 Subject: [PATCH 072/179] Bump node-fetch from 3.2.9 to 3.2.10 in /typescript Bumps [node-fetch](https://github.com/node-fetch/node-fetch) from 3.2.9 to 3.2.10. - [Release notes](https://github.com/node-fetch/node-fetch/releases) - [Commits](https://github.com/node-fetch/node-fetch/compare/v3.2.9...v3.2.10) --- updated-dependencies: - dependency-name: node-fetch dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- typescript/package-lock.json | 14 +++++++------- typescript/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/typescript/package-lock.json b/typescript/package-lock.json index 8e498e884..15653acc2 100644 --- a/typescript/package-lock.json +++ b/typescript/package-lock.json @@ -8,7 +8,7 @@ "name": "Bangle.ts", "version": "0.0.1", "dependencies": { - "node-fetch": "^3.2.9" + "node-fetch": "^3.2.10" }, "devDependencies": { "typescript": "4.5.2" @@ -74,9 +74,9 @@ } }, "node_modules/node-fetch": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.9.tgz", - "integrity": "sha512-/2lI+DBecVvVm9tDhjziTVjo2wmTsSxSk58saUYP0P/fRJ3xxtfMDY24+CKTkfm0Dlhyn3CSXNL0SoRiCZ8Rzg==", + "version": "3.2.10", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.10.tgz", + "integrity": "sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==", "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", @@ -141,9 +141,9 @@ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" }, "node-fetch": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.9.tgz", - "integrity": "sha512-/2lI+DBecVvVm9tDhjziTVjo2wmTsSxSk58saUYP0P/fRJ3xxtfMDY24+CKTkfm0Dlhyn3CSXNL0SoRiCZ8Rzg==", + "version": "3.2.10", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.10.tgz", + "integrity": "sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==", "requires": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", diff --git a/typescript/package.json b/typescript/package.json index 070257cc0..9533d77a7 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -10,6 +10,6 @@ "build": "tsc" }, "dependencies": { - "node-fetch": "^3.2.9" + "node-fetch": "^3.2.10" } } From b2e4e89910d75de03c55184d7f3b15e6c8002d1f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Nov 2022 08:29:13 +0000 Subject: [PATCH 073/179] Bump got and nodemon Removes [got](https://github.com/sindresorhus/got). It's no longer used after updating ancestor dependency [nodemon](https://github.com/remy/nodemon). These dependencies need to be updated together. Removes `got` Updates `nodemon` from 2.0.16 to 2.0.20 - [Release notes](https://github.com/remy/nodemon/releases) - [Commits](https://github.com/remy/nodemon/compare/v2.0.16...v2.0.20) --- updated-dependencies: - dependency-name: got dependency-type: indirect - dependency-name: nodemon dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 611 ++-------------------------------------------- 1 file changed, 19 insertions(+), 592 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6872e616c..e981abdb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,21 +38,6 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true - }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, - "requires": { - "defer-to-connect": "^1.0.1" - } - }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -88,15 +73,6 @@ "uri-js": "^4.2.2" } }, - "ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "requires": { - "string-width": "^4.1.0" - } - }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -165,22 +141,6 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, - "boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, - "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - } - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -200,38 +160,6 @@ "fill-range": "^7.0.1" } }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - } - } - }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -248,12 +176,6 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -291,27 +213,6 @@ } } }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -333,20 +234,6 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - } - }, "confusing-browser-globals": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", @@ -364,12 +251,6 @@ "which": "^2.0.1" } }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true - }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -379,33 +260,12 @@ "ms": "2.1.2" } }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, "define-properties": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", @@ -425,36 +285,6 @@ "esutils": "^2.0.2" } }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, "es-abstract": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", @@ -506,12 +336,6 @@ "is-symbol": "^1.0.2" } }, - "escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true - }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -859,15 +683,6 @@ "has-symbols": "^1.0.3" } }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, "get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", @@ -901,15 +716,6 @@ "is-glob": "^4.0.3" } }, - "global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dev": true, - "requires": { - "ini": "2.0.0" - } - }, "globals": { "version": "13.15.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", @@ -919,31 +725,6 @@ "type-fest": "^0.20.2" } }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -989,18 +770,6 @@ "has-symbols": "^1.0.2" } }, - "has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -1023,12 +792,6 @@ "resolve-from": "^4.0.0" } }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", - "dev": true - }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -1051,12 +814,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true - }, "internal-slot": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", @@ -1102,15 +859,6 @@ "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "dev": true }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, "is-core-module": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", @@ -1135,12 +883,6 @@ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -1150,28 +892,12 @@ "is-extglob": "^2.1.1" } }, - "is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - } - }, "is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "dev": true }, - "is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", - "dev": true - }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -1187,18 +913,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -1236,12 +950,6 @@ "has-symbols": "^1.0.2" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, "is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -1251,12 +959,6 @@ "call-bind": "^1.0.2" } }, - "is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1272,12 +974,6 @@ "argparse": "^2.0.1" } }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", - "dev": true - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -1299,24 +995,6 @@ "minimist": "^1.2.0" } }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "requires": { - "json-buffer": "3.0.0" - } - }, - "latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dev": true, - "requires": { - "package-json": "^6.3.0" - } - }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1343,36 +1021,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1401,21 +1049,21 @@ "dev": true }, "nodemon": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.16.tgz", - "integrity": "sha512-zsrcaOfTWRuUzBn3P44RDliLlp263Z/76FPoHFr3cFFkOz0lTPAcIw8dCzfdVIx/t3AtDYCZRCDkoCojJqaG3w==", + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", "dev": true, "requires": { "chokidar": "^3.5.2", "debug": "^3.2.7", "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", "supports-color": "^5.5.0", "touch": "^3.1.0", - "undefsafe": "^2.0.5", - "update-notifier": "^5.1.0" + "undefsafe": "^2.0.5" }, "dependencies": { "debug": { @@ -1465,12 +1113,6 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true - }, "npm-watch": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/npm-watch/-/npm-watch-0.11.0.tgz", @@ -1550,12 +1192,6 @@ "word-wrap": "^1.2.3" } }, - "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true - }, "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", @@ -1580,18 +1216,6 @@ "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", "dev": true }, - "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "dev": true, - "requires": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - } - }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -1637,69 +1261,18 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", - "dev": true - }, "pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, - "pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dev": true, - "requires": { - "escape-goat": "^2.0.0" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true - } - } - }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -1737,24 +1310,6 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, - "registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, - "registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, "resolve": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", @@ -1772,15 +1327,6 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", - "dev": true, - "requires": { - "lowercase-keys": "^1.0.0" - } - }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -1802,15 +1348,6 @@ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, - "semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "requires": { - "semver": "^6.3.0" - } - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -1837,21 +1374,21 @@ "object-inspect": "^1.9.0" } }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "simple-update-notifier": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", + "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", "dev": true, "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "semver": "~7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } } }, "string.prototype.trimend": { @@ -1936,12 +1473,6 @@ "readable-stream": "3" } }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1987,15 +1518,6 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, "unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -2014,48 +1536,6 @@ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "dev": true }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "requires": { - "crypto-random-string": "^2.0.0" - } - }, - "update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", - "dev": true, - "requires": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "dependencies": { - "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -2065,15 +1545,6 @@ "punycode": "^2.1.0" } }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", - "dev": true, - "requires": { - "prepend-http": "^2.0.0" - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -2108,61 +1579,17 @@ "is-symbol": "^1.0.3" } }, - "widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "requires": { - "string-width": "^4.0.0" - } - }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true } } } From 1b1f1d776b3f51543a8b0f67e4975f2ac73b6ca3 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 4 Nov 2022 10:07:53 +0000 Subject: [PATCH 074/179] settings 0.54: If setting.json is corrupt, ensure it gets re-written --- apps/setting/ChangeLog | 1 + apps/setting/metadata.json | 2 +- apps/setting/settings.js | 26 ++++++++++++++------------ 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog index cd97e1dda..55b61c46a 100644 --- a/apps/setting/ChangeLog +++ b/apps/setting/ChangeLog @@ -58,3 +58,4 @@ 0.51: Add setting for configuring a launcher 0.52: Add option for left-handed users 0.53: Ensure that when clock is set, clockHasWidgets is set correctly too +0.54: If setting.json is corrupt, ensure it gets re-written diff --git a/apps/setting/metadata.json b/apps/setting/metadata.json index 47d0a309f..08544cff6 100644 --- a/apps/setting/metadata.json +++ b/apps/setting/metadata.json @@ -1,7 +1,7 @@ { "id": "setting", "name": "Settings", - "version": "0.53", + "version": "0.54", "description": "A menu for setting up Bangle.js", "icon": "settings.png", "tags": "tool,system", diff --git a/apps/setting/settings.js b/apps/setting/settings.js index d7bb060ea..2350a8965 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -60,7 +60,9 @@ function resetSettings() { } settings = storage.readJSON('setting.json', 1); -if (!settings) resetSettings(); +if (("object" != typeof settings) || + ("object" != typeof settings.options)) + resetSettings(); const boolFormat = v => v ? /*LANG*/"On" : /*LANG*/"Off"; @@ -237,9 +239,9 @@ function showThemeMenu() { } }; - require("Storage").list(/^.*\.theme$/).forEach( + storage.list(/^.*\.theme$/).forEach( n => { - let newTheme = require("Storage").readJSON(n); + let newTheme = storage.readJSON(n); themesMenu[newTheme.name ? newTheme.name : n] = () => { upd({ fg:cl(newTheme.fg), bg:cl(newTheme.bg), @@ -567,11 +569,11 @@ function showUtilMenu() { }, /*LANG*/'Compact Storage': () => { E.showMessage(/*LANG*/"Compacting...\nTakes approx\n1 minute",{title:/*LANG*/"Storage"}); - require("Storage").compact(); + storage.compact(); showUtilMenu(); }, /*LANG*/'Rewrite Settings': () => { - require("Storage").write(".boot0","eval(require('Storage').read('bootupdate.js'));"); + storage.write(".boot0","eval(require('Storage').read('bootupdate.js'));"); load("setting.app.js"); }, /*LANG*/'Flatten Battery': () => { @@ -592,9 +594,9 @@ function showUtilMenu() { menu[/*LANG*/'Calibrate Battery'] = () => { E.showPrompt(/*LANG*/"Is the battery fully charged?",{title:/*LANG*/"Calibrate"}).then(ok => { if (ok) { - var s=require("Storage").readJSON("setting.json"); + var s=storage.readJSON("setting.json"); s.batFullVoltage = (analogRead(D3)+analogRead(D3)+analogRead(D3)+analogRead(D3))/4; - require("Storage").writeJSON("setting.json",s); + storage.writeJSON("setting.json",s); E.showAlert(/*LANG*/"Calibrated!").then(() => load("setting.app.js")); } else { E.showAlert(/*LANG*/"Please charge Bangle.js for 3 hours and try again").then(() => load("settings.app.js")); @@ -659,7 +661,7 @@ function makeConnectable() { }); } function showClockMenu() { - var clockApps = require("Storage").list(/\.info$/) + var clockApps = storage.list(/\.info$/) .map(app => {var a=storage.readJSON(app, 1);return (a&&a.type == "clock")?a:undefined}) .filter(app => app) // filter out any undefined apps .sort((a, b) => a.sortorder - b.sortorder); @@ -676,7 +678,7 @@ function showClockMenu() { } clockMenu[label] = () => { settings.clock = app.src; - settings.clockHasWidgets = require("Storage").read(app.src).includes("Bangle.loadWidgets"); + settings.clockHasWidgets = storage.read(app.src).includes("Bangle.loadWidgets"); updateSettings(); showMainMenu(); }; @@ -687,7 +689,7 @@ function showClockMenu() { return E.showMenu(clockMenu); } function showLauncherMenu() { - var launcherApps = require("Storage").list(/\.info$/) + var launcherApps = storage.list(/\.info$/) .map(app => {var a=storage.readJSON(app, 1);return (a&&a.type == "launch")?a:undefined}) .filter(app => app) // filter out any undefined apps .sort((a, b) => a.sortorder - b.sortorder); @@ -865,9 +867,9 @@ function showTouchscreenCalibration() { Bangle.setOptions({ touchX1: calib.x1, touchY1: calib.y1, touchX2: calib.x2, touchY2: calib.y2 }); - var s = require("Storage").readJSON("setting.json",1)||{}; + var s = storage.readJSON("setting.json",1)||{}; s.touch = calib; - require("Storage").writeJSON("setting.json",s); + storage.writeJSON("setting.json",s); g.setFont("6x8:2").setFontAlign(0,0).drawString("Calibrated!", g.getWidth()/2, g.getHeight()/2); // now load the main menu again setTimeout(showLCDMenu, 500); From 69dbac612841848a09a1fe6e8a9f4e349afb7b85 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 4 Nov 2022 11:50:27 +0000 Subject: [PATCH 075/179] Add require("clock_info").addInteractive to allow info displays to be added to the screen easily (ref #2226) --- modules/clock_info.js | 63 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/modules/clock_info.js b/modules/clock_info.js index 76a93ba49..b87c022f2 100644 --- a/modules/clock_info.js +++ b/modules/clock_info.js @@ -111,12 +111,71 @@ exports.load = function() { return menu; }; +/** Adds an interactive menu that could be used on a clock face by swiping. +Simply supply the menu data (from .load) and a function to draw the clock info. -// Code for testing +For example: + +var clockInfoMenu = require("clock_info").addInteractive(require("clock_info").load(), (itm, info) => { + var y = 0; + g.reset().setFont("6x8:2").setFontAlign(-1,0); + g.clearRect(0,y,g.getWidth(),y+23); + g.drawImage(info.img, 0,y); + g.drawString(info.text, 48,y+12); +}); + +Then if you need to unload the clock info so it no longer +uses memory or responds to swipes, you can call clockInfoMenu.remove() +and delete clockInfoMenu +*/ +exports.addInteractive = function(menu, drawFn) { + if (!menu.length || !menu[0].items.length) return; // no info + var menuA = 0, menuB = 0; + function menuShowItem(itm) { + itm.on('redraw', ()=>drawFn(itm, itm.get())); + itm.show(); + itm.emit("redraw"); + } + // handling for swipe between menu items + function swipeHandler(lr,ud){ + var oldMenuItem; + if (ud) { + if (menu[menuA].items.length==1) return; // 1 item - can't move + oldMenuItem = menu[menuA].items[menuB]; + menuB += ud; + if (menuB<0) menuB = menu[menuA].items.length-1; + if (menuB>=menu[menuA].items.length) menuB = 0; + } else if (lr) { + if (menu.length==1) return; // 1 item - can't move + oldMenuItem = menu[menuA].items[menuB]; + menuA += ud; + if (menuA<0) menuA = menu.length-1; + if (menuA>=menu.length) menuA = 0; + menuB = 0; + } + if (oldMenuItem) { + oldMenuItem.hide(); + oldMenuItem.removeAllListeners("draw"); + menuShowItem(menu[menuA].items[menuB]); + } + } + Bangle.on("swipe",swipeHandler); + // draw the first item + menuShowItem(menu[menuA].items[menuB]); + // return an object with info that can be used to remove the info + return { + remove : function() { + Bangle.removeListener("swipe",swipeHandler); + menu[menuA].items[menuB].hide(); + } + }; +}; + +// Code for testing (plots all elements from first list) /* g.clear(); var menu = exports.load(); // or require("clock_info").load() -var itemsFirstMenu = menu[0].items; +var items = menu[0].items; items.forEach((itm,i) => { var y = i*24; console.log("Starting", itm.name); From ba028e1f58d8928189c5ee33e2eb588acc9e177f Mon Sep 17 00:00:00 2001 From: Rarder44 Date: Fri, 4 Nov 2022 15:06:10 +0100 Subject: [PATCH 076/179] implemented widget_utils --- apps/rebble/ChangeLog | 3 ++- apps/rebble/metadata.json | 2 +- apps/rebble/rebble.app.js | 10 +--------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/apps/rebble/ChangeLog b/apps/rebble/ChangeLog index c392cc74b..21dd44e77 100644 --- a/apps/rebble/ChangeLog +++ b/apps/rebble/ChangeLog @@ -8,4 +8,5 @@ 0.08: removed unused font, fix autocycle, imported suncalc and trimmed, removed pedometer dependency, "tap to cycle" setting 0.09: fix battery icon size 0.10: Tell clock widgets to hide. -0.11: fix issue https://github.com/espruino/BangleApps/issues/2128 (#2128) ( settings undefined ) \ No newline at end of file +0.11: fix issue https://github.com/espruino/BangleApps/issues/2128 (#2128) ( settings undefined ) +0.12: implemented widget_utils \ No newline at end of file diff --git a/apps/rebble/metadata.json b/apps/rebble/metadata.json index 9134ccd23..dfc0703c0 100644 --- a/apps/rebble/metadata.json +++ b/apps/rebble/metadata.json @@ -2,7 +2,7 @@ "id": "rebble", "name": "Rebble Clock", "shortName": "Rebble", - "version": "0.11", + "version": "0.12", "description": "A Pebble style clock, with configurable background, three sidebars including steps, day, date, sunrise, sunset, long live the rebellion", "readme": "README.md", "icon": "rebble.png", diff --git a/apps/rebble/rebble.app.js b/apps/rebble/rebble.app.js index 2ddd3a9b9..82e4a62d7 100644 --- a/apps/rebble/rebble.app.js +++ b/apps/rebble/rebble.app.js @@ -309,16 +309,8 @@ else{ } -g.clear(); Bangle.loadWidgets(); -/* - * we are not drawing the widgets as we are taking over the whole screen - * so we will blank out the draw() functions of each widget and change the - * area to the top bar doesn't get cleared. - */ -for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";} - - +require("widget_utils").hide(); From 73cbbb21df4c41010367b8ef169dc7f546dfcdc1 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 4 Nov 2022 14:10:03 +0000 Subject: [PATCH 077/179] launcher 0.18: Add 'back' icon in top-left to go back to clock --- apps/launch/ChangeLog | 1 + apps/launch/app.js | 24 ++++++++++++++---------- apps/launch/metadata.json | 2 +- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/apps/launch/ChangeLog b/apps/launch/ChangeLog index 65f671bbd..955061e19 100644 --- a/apps/launch/ChangeLog +++ b/apps/launch/ChangeLog @@ -17,3 +17,4 @@ 0.15: Support for unload and quick return to the clock on 2v16 0.16: Use a cache of app.info files to speed up loading the launcher 0.17: Don't display 'Loading...' now the watch has its own loading screen +0.18: Add 'back' icon in top-left to go back to clock diff --git a/apps/launch/app.js b/apps/launch/app.js index 3b33e530a..e9f99d8f5 100644 --- a/apps/launch/app.js +++ b/apps/launch/app.js @@ -41,6 +41,17 @@ let apps = launchCache.apps; // Now apps list is loaded - render if (!settings.fullscreen) Bangle.loadWidgets(); + +let returnToClock = function() { + // unload everything manually + // ... or we could just call `load();` but it will be slower + Bangle.setUI(); // remove scroller's handling + if (lockTimeout) clearTimeout(lockTimeout); + Bangle.removeListener("lock", lockHandler); + // now load the default clock - just call .bootcde as this has the code already + setTimeout(eval,0,s.read(".bootcde")); +} + E.showScroller({ h : 64*scaleval, c : apps.length, draw : (i, r) => { @@ -62,19 +73,12 @@ E.showScroller({ } else { load(app.src); } - } + }, + back : returnToClock }); g.flip(); // force a render before widgets have finished drawing -let returnToClock = function() { - // unload everything manually - // ... or we could just call `load();` but it will be slower - Bangle.setUI(); // remove scroller's handling - if (lockTimeout) clearTimeout(lockTimeout); - Bangle.removeListener("lock", lockHandler); - // now load the default clock - just call .bootcde as this has the code already - setTimeout(eval,0,s.read(".bootcde")); -} + // on bangle.js 2, the screen is used for navigating, so the single button goes back // on bangle.js 1, the buttons are used for navigating diff --git a/apps/launch/metadata.json b/apps/launch/metadata.json index 8d6d90fb1..d6770524c 100644 --- a/apps/launch/metadata.json +++ b/apps/launch/metadata.json @@ -2,7 +2,7 @@ "id": "launch", "name": "Launcher", "shortName": "Launcher", - "version": "0.17", + "version": "0.18", "description": "This is needed to display a menu allowing you to choose your own applications. You can replace this with a customised launcher.", "readme": "README.md", "icon": "app.png", From 45eb06fbd1ae155cb6430adccac2cf3ead8284f1 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 4 Nov 2022 14:10:18 +0000 Subject: [PATCH 078/179] swiper 0.04: Update to work with new 'fast switch' clock->launcher functionality --- apps/swiperclocklaunch/ChangeLog | 1 + apps/swiperclocklaunch/boot.js | 30 ++++++++++++++-------------- apps/swiperclocklaunch/metadata.json | 2 +- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/apps/swiperclocklaunch/ChangeLog b/apps/swiperclocklaunch/ChangeLog index 244b602b5..e7ad4555c 100644 --- a/apps/swiperclocklaunch/ChangeLog +++ b/apps/swiperclocklaunch/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Fix issue with mode being undefined 0.03: Update setUI to work with new Bangle.js 2v13 menu style +0.04: Update to work with new 'fast switch' clock->launcher functionality diff --git a/apps/swiperclocklaunch/boot.js b/apps/swiperclocklaunch/boot.js index bb285ea94..ea00a6735 100644 --- a/apps/swiperclocklaunch/boot.js +++ b/apps/swiperclocklaunch/boot.js @@ -1,19 +1,19 @@ -// clock -> launcher (function() { - var sui = Bangle.setUI; - Bangle.setUI = function(mode, cb) { - sui(mode,cb); - if(!mode) return; - if ("object"==typeof mode) mode = mode.mode; - if (!mode.startsWith("clock")) return; - Bangle.swipeHandler = dir => { if (dir<0) Bangle.showLauncher(); }; - Bangle.on("swipe", Bangle.swipeHandler); - }; -})(); -// launcher -> clock -setTimeout(function() { - if (global.__FILE__ && __FILE__.endsWith(".app.js") && (require("Storage").readJSON(__FILE__.slice(0,-6)+"info",1)||{}).type=="launch") { + var sui = Bangle.setUI; + Bangle.setUI = function(mode, cb) { + sui(mode,cb); + if(!mode) return; + if ("object"==typeof mode) mode = mode.mode; + if (mode.startsWith("clock")) { + // clock -> launcher + Bangle.swipeHandler = dir => { if (dir<0) Bangle.showLauncher(); }; + Bangle.on("swipe", Bangle.swipeHandler); + } else { + if (global.__FILE__ && __FILE__.endsWith(".app.js") && (require("Storage").readJSON(__FILE__.slice(0,-6)+"info",1)||{}).type=="launch") { + // launcher -> clock Bangle.swipeHandler = dir => { if (dir>0) load(); }; Bangle.on("swipe", Bangle.swipeHandler); + } } -}, 10); + }; +})(); diff --git a/apps/swiperclocklaunch/metadata.json b/apps/swiperclocklaunch/metadata.json index 5e4a0d648..4f27da528 100644 --- a/apps/swiperclocklaunch/metadata.json +++ b/apps/swiperclocklaunch/metadata.json @@ -1,7 +1,7 @@ { "id": "swiperclocklaunch", "name": "Swiper Clock Launch", - "version": "0.03", + "version": "0.04", "description": "Navigate between clock and launcher with Swipe action", "icon": "swiperclocklaunch.png", "type": "bootloader", From adc59dcc164dd1feb1be1feedac1d2279b66cc55 Mon Sep 17 00:00:00 2001 From: Rarder44 Date: Fri, 4 Nov 2022 15:57:14 +0100 Subject: [PATCH 079/179] changed the launch.json file name in iconlaunch.json ( launch.cache.json -> iconlaunch.cache.json) used Object.assing for the settings fix cache not deleted when "showClocks" options is changed added timeOut to return to the clock --- apps/iconlaunch/ChangeLog | 4 ++++ apps/iconlaunch/app.js | 22 ++++++++++++++++++---- apps/iconlaunch/metadata.json | 3 ++- apps/iconlaunch/settings.js | 25 +++++++++++++++++++------ 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/apps/iconlaunch/ChangeLog b/apps/iconlaunch/ChangeLog index eca18b06c..c71da1467 100644 --- a/apps/iconlaunch/ChangeLog +++ b/apps/iconlaunch/ChangeLog @@ -8,3 +8,7 @@ Add swipe-to-exit 0.08: Only use fast loading for switching to clock to prevent problems in full screen apps 0.09: Remove fast load option since clocks containing Bangle.loadWidgets are now always normally loaded +0.10: changed the launch.json file name in iconlaunch.json ( launch.cache.json -> iconlaunch.cache.json) + used Object.assing for the settings + fix cache not deleted when "showClocks" options is changed + added timeOut to return to the clock diff --git a/apps/iconlaunch/app.js b/apps/iconlaunch/app.js index 8d2f1ec4c..479956019 100644 --- a/apps/iconlaunch/app.js +++ b/apps/iconlaunch/app.js @@ -1,12 +1,21 @@ { const s = require("Storage"); - const settings = s.readJSON("launch.json", true) || { showClocks: true, fullscreen: false,direct:false,swipeExit:false,oneClickExit:false}; + const settings = Object.assign({ + showClocks: true, + fullscreen: false, + direct: false, + oneClickExit: false, + swipeExit: false, + timeOut:"Off" + }, s.readJSON("iconlaunch.json", true) || {}); + + console.log(settings); if (!settings.fullscreen) { Bangle.loadWidgets(); Bangle.drawWidgets(); } - let launchCache = s.readJSON("launch.cache.json", true)||{}; - let launchHash = require("Storage").hash(/\.info/); + let launchCache = s.readJSON("iconlaunch.cache.json", true)||{}; + let launchHash = s.hash(/\.info/); if (launchCache.hash!=launchHash) { launchCache = { hash : launchHash, @@ -20,7 +29,7 @@ if (a.name>b.name) return 1; return 0; }) }; - s.writeJSON("launch.cache.json", launchCache); + s.writeJSON("iconlaunch.cache.json", launchCache); } let scroll = 0; let selectedItem = -1; @@ -198,6 +207,11 @@ if (settings.oneClickExit) mode.btn = returnToClock; + if (settings.timeOut!="Off"){ + let time=parseInt(settings.timeOut); //the "s" will be trimmed by the parseInt + setTimeout(returnToClock,time*1000); + } + Bangle.setUI(mode); } diff --git a/apps/iconlaunch/metadata.json b/apps/iconlaunch/metadata.json index e310ede4d..13e7aee08 100644 --- a/apps/iconlaunch/metadata.json +++ b/apps/iconlaunch/metadata.json @@ -2,7 +2,7 @@ "id": "iconlaunch", "name": "Icon Launcher", "shortName" : "Icon launcher", - "version": "0.09", + "version": "0.10", "icon": "app.png", "description": "A launcher inspired by smartphones, with an icon-only scrollable menu.", "tags": "tool,system,launcher", @@ -12,6 +12,7 @@ { "name": "iconlaunch.app.js", "url": "app.js" }, { "name": "iconlaunch.settings.js", "url": "settings.js" } ], + "data": [{"name":"iconlaunch.json"},{"name":"iconlaunch.cache.json"}], "screenshots": [{ "url": "screenshot1.png" }, { "url": "screenshot2.png" }], "readme": "README.md" } diff --git a/apps/iconlaunch/settings.js b/apps/iconlaunch/settings.js index 49a49f700..f4c0599f7 100644 --- a/apps/iconlaunch/settings.js +++ b/apps/iconlaunch/settings.js @@ -1,24 +1,29 @@ // make sure to enclose the function in parentheses (function(back) { + const s = require("Storage"); let settings = Object.assign({ showClocks: true, fullscreen: false, direct: false, oneClickExit: false, - swipeExit: false - }, require("Storage").readJSON("launch.json", true) || {}); + swipeExit: false, + timeOut:"Off" + }, s.readJSON("iconlaunch.json", true) || {}); - let fonts = g.getFonts(); function save(key, value) { settings[key] = value; - require("Storage").write("launch.json",settings); + s.write("iconlaunch.json",settings); } + const timeOutChoices = [/*LANG*/"Off", "10s", "15s", "20s", "30s"]; const appMenu = { "": { "title": /*LANG*/"Launcher" }, /*LANG*/"< Back": back, /*LANG*/"Show Clocks": { value: settings.showClocks == true, - onchange: (m) => { save("showClocks", m) } + onchange: (m) => { + save("showClocks", m); + s.erase("iconlaunch.cache.json"); //delete the cache app list + } }, /*LANG*/"Fullscreen": { value: settings.fullscreen == true, @@ -35,7 +40,15 @@ /*LANG*/"Swipe exit": { value: settings.swipeExit == true, onchange: m => { save("swipeExit", m) } - } + }, + /*LANG*/'Time Out': { + value: timeOutChoices.indexOf(settings.timeOut), + min: 0, max: timeOutChoices.length-1, + format: v => timeOutChoices[v], + onchange: m => { + save("timeOut", timeOutChoices[m]); + } + }, }; E.showMenu(appMenu); }); From d3c284ac8e84466a0a7d50fceadc5e736cf9a1d0 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 4 Nov 2022 15:14:05 +0000 Subject: [PATCH 080/179] Support for sort by installs/sort by favourites --- core | 2 +- css/main.css | 17 ++++++++++++++--- index.html | 6 ++++-- loader.js | 3 +++ 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/core b/core index 80de03d8e..87cf54203 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 80de03d8e665c210dc3443d6869176c848ab103f +Subproject commit 87cf5420322cd78a13e3d2b76cd12c9fdbddc7d2 diff --git a/css/main.css b/css/main.css index 96a102119..ceb9fcd17 100644 --- a/css/main.css +++ b/css/main.css @@ -30,7 +30,7 @@ } a.mr-2{ - display: flex; + display: flex; align-items: center; } @@ -102,12 +102,23 @@ a.btn.btn-link.dropdown-toggle { content: url("data:image/svg+xml,%3Csvg fill='rgb(87, 85, 217)' xmlns='http://www.w3.org/2000/svg' viewBox='4 4 40 40' width='1em' height='1em'%3E%3Cpath d='M 8.5 5 C 6.0324991 5 4 7.0324991 4 9.5 L 4 30.5 C 4 32.967501 6.0324991 35 8.5 35 L 17 35 L 17 40 L 13.5 40 A 1.50015 1.50015 0 1 0 13.5 43 L 18.253906 43 A 1.50015 1.50015 0 0 0 18.740234 43 L 29.253906 43 A 1.50015 1.50015 0 0 0 29.740234 43 L 34.5 43 A 1.50015 1.50015 0 1 0 34.5 40 L 31 40 L 31 35 L 39.5 35 C 41.967501 35 44 32.967501 44 30.5 L 44 9.5 C 44 7.0324991 41.967501 5 39.5 5 L 8.5 5 z M 8.5 8 L 39.5 8 C 40.346499 8 41 8.6535009 41 9.5 L 41 30.5 C 41 31.346499 40.346499 32 39.5 32 L 29.746094 32 A 1.50015 1.50015 0 0 0 29.259766 32 L 18.746094 32 A 1.50015 1.50015 0 0 0 18.259766 32 L 8.5 32 C 7.6535009 32 7 31.346499 7 30.5 L 7 9.5 C 7 8.6535009 7.6535009 8 8.5 8 z M 17.5 12 C 16.136406 12 15 13.136406 15 14.5 L 15 25.5 C 15 26.863594 16.136406 28 17.5 28 L 30.5 28 C 31.863594 28 33 26.863594 33 25.5 L 33 14.5 C 33 13.136406 31.863594 12 30.5 12 L 17.5 12 z M 18 18 L 30 18 L 30 25 L 18 25 L 18 18 z M 20 35 L 28 35 L 28 40 L 20 40 L 20 35 z'/%3E%3C/svg%3E"); } .icon.icon-favourite { text-indent: 0px; } /*override spectre*/ +.icon.icon-favourite-active { text-indent: 0px; } /*override spectre*/ .icon.icon-favourite::before { - content: "\02661"; /* 0x2661 = empty heart; 0x2606 = empty star */ + content: url("data:image/svg+xml,%3Csvg fill='rgb(255, 0, 0)' xmlns='http://www.w3.org/2000/svg' viewBox='0 -3 50 47' width='1.5em' height='1.5em'%3E%3Cpath d='M 16.375 9 C 10.117188 9 5 14.054688 5 20.28125 C 5 33.050781 19.488281 39.738281 24.375 43.78125 L 25 44.3125 L 25.625 43.78125 C 30.511719 39.738281 45 33.050781 45 20.28125 C 45 14.054688 39.882813 9 33.625 9 C 30.148438 9 27.085938 10.613281 25 13.0625 C 22.914063 10.613281 19.851563 9 16.375 9 Z M 16.375 11 C 19.640625 11 22.480469 12.652344 24.15625 15.15625 L 25 16.40625 L 25.84375 15.15625 C 27.519531 12.652344 30.359375 11 33.625 11 C 38.808594 11 43 15.144531 43 20.28125 C 43 31.179688 30.738281 37.289063 25 41.78125 C 19.261719 37.289063 7 31.179688 7 20.28125 C 7 15.144531 11.1875 11 16.375 11 Z'/%3E%3C/svg%3E"); } .icon.icon-favourite-active::before { - content: "\02665"; /* 0x2665 = solid heart; 0x2605 = solid star */ + content: url("data:image/svg+xml,%3Csvg fill='rgb(255, 0, 0)' xmlns='http://www.w3.org/2000/svg' viewBox='0 -3 50 47' width='1.5em' height='1.5em'%3E%3Cpath d='M 25 44.296875 L 24.363281 43.769531 C 23.363281 42.941406 22.019531 42.027344 20.46875 40.96875 C 14.308594 36.765625 5 30.414063 5 20.285156 C 5 14.0625 10.097656 9 16.363281 9 C 19.714844 9 22.851563 10.457031 25 12.957031 C 27.148438 10.457031 30.289063 9 33.636719 9 C 39.902344 9 45 14.0625 45 20.285156 C 45 30.414063 35.691406 36.765625 29.53125 40.96875 C 27.976563 42.027344 26.636719 42.941406 25.636719 43.769531 Z'/%3E%3C/svg%3E"); } +.icon.icon-favourite span { + font-size: 50%; + color : #F66; + position:relative; + top:-0.7em; +} +.icon.icon-favourite-active span { + color : white; +} + .icon.icon-interface {text-indent: 0px;} /*override spectre*/ .icon.icon-interface::before { position: absolute; left: 50%; top: 70%; diff --git a/index.html b/index.html index a322da77b..e037ee7aa 100644 --- a/index.html +++ b/index.html @@ -88,8 +88,10 @@ diff --git a/loader.js b/loader.js index 9d97b45b5..3a6b41cfe 100644 --- a/loader.js +++ b/loader.js @@ -21,6 +21,9 @@ var RECOMMENDED_VERSION = "2v15"; // We're only interested in Bangles DEVICEINFO = DEVICEINFO.filter(x=>x.id.startsWith("BANGLEJS")); +// Where we get our usage data from +Const.APP_USAGE_JSON = "https://banglejs.com/apps/appusage.json"; +Const.APP_DATES_CSV = "appdates.csv"; // Set up source code URL (function() { From 60885e43b1b7f9bdc44431542f0ad83b78669694 Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Fri, 4 Nov 2022 17:39:55 +0200 Subject: [PATCH 081/179] Create ChangeLog --- apps/pisteinen/ChangeLog | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/pisteinen/ChangeLog diff --git a/apps/pisteinen/ChangeLog b/apps/pisteinen/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/pisteinen/ChangeLog @@ -0,0 +1 @@ +0.01: New App! From 099277673adc895a2d9273b2bff83f5ec2e7c13a Mon Sep 17 00:00:00 2001 From: jukioo <100193873+jukioo@users.noreply.github.com> Date: Fri, 4 Nov 2022 17:40:28 +0200 Subject: [PATCH 082/179] Create ChangeLog --- apps/palikkainen/ChangeLog | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/palikkainen/ChangeLog diff --git a/apps/palikkainen/ChangeLog b/apps/palikkainen/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/palikkainen/ChangeLog @@ -0,0 +1 @@ +0.01: New App! From 5c110a89fb08dd2c92024fff39d7ab0101d3a162 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 4 Nov 2022 15:52:32 +0000 Subject: [PATCH 083/179] tweak screenshot sizes --- apps/henkinen/screenshot1.png | Bin 17968 -> 13764 bytes apps/palikkainen/screenshot1.png | Bin 31010 -> 13973 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/henkinen/screenshot1.png b/apps/henkinen/screenshot1.png index 751fc30add2fcca4f373b499287795f974315f38..9384946737ddaba25cf12201dffb56355847a795 100644 GIT binary patch delta 10455 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 literal 17968 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 YVJ%#PCGLIX%Lst3mZ4^qy7Q&~0U330KL7v# literal 31010 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 From 02a931f5fd675c4e0b7610e4262eafe455728d63 Mon Sep 17 00:00:00 2001 From: hugh Date: Sat, 5 Nov 2022 00:27:49 +0000 Subject: [PATCH 084/179] Added PrimeTimeLato app --- apps/primetimelato/README.md | 13 ++++ apps/primetimelato/app.js | 106 ++++++++++++++++++++++++++++++ apps/primetimelato/app.png | Bin 0 -> 710 bytes apps/primetimelato/icon.js | 1 + apps/primetimelato/metadata.json | 15 +++++ apps/primetimelato/screenshot.png | Bin 0 -> 2287 bytes 6 files changed, 135 insertions(+) create mode 100644 apps/primetimelato/README.md create mode 100644 apps/primetimelato/app.js create mode 100644 apps/primetimelato/app.png create mode 100644 apps/primetimelato/icon.js create mode 100644 apps/primetimelato/metadata.json create mode 100644 apps/primetimelato/screenshot.png diff --git a/apps/primetimelato/README.md b/apps/primetimelato/README.md new file mode 100644 index 000000000..6760fe41a --- /dev/null +++ b/apps/primetimelato/README.md @@ -0,0 +1,13 @@ +# Prime Time Lato (clock) + +A watchface that displays time and its prime factors in the Lato font. +For example when the time is 21:05, the prime factors are 5,421. +Displays 'Prime Time!' when the time is a prime number. + +![](screenshot.jpg) + +Written by: [Hugh Barney](https://github.com/hughbarney) + +Adapted from primetime by [Eve Bury](https://www.github.com/eveeeon) + +For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/primetimelato/app.js b/apps/primetimelato/app.js new file mode 100644 index 000000000..2031fd53b --- /dev/null +++ b/apps/primetimelato/app.js @@ -0,0 +1,106 @@ +const h = g.getHeight(); +const w = g.getWidth(); + +Graphics.prototype.setFontLato = function(scale) { + // Actual height 41 (43 - 3) + this.setFontCustom( + E.toString(require('heatshrink').decompress(atob('ACEfAokB/AGEn+AAocDBgsfBgkB+A6Yg4FEgYgF/4FEv/gHIhAEh/+DwgYEgP/4AeJn4eF/hDEDwxrE/4eFKAgeFgJDERQ5DEXJI0Eh//IIZlB/4pDAoP/HgQYBAAIaBPARDDv4JBj5WBh5ZCv4CBPATPCeQcPwDYECAIMGPId4gEeSIYMHDIYMCExZAGh6ICn5QEK4RnGOgqBGaoKOECYSiDn78FAFgxFR4bcCKISOBgF+RwYCBTgQMCOIQMCj5eCBgIfDBgQfCBgSbDWoSHC/61CAwYMUAAYzCAAZNCBkYAfgYmBgJ7CTYsPTYQMBgJnBgYMCn4MBv64CBgMPXYSBBD4cfBgQIBgf3RwK7CvybCGQXPBgIfBGQIMBeoU/DoIMCF4IMDgP8BgQmBn8AEwb+BBgQIBIQJAC4BYBIgTNBDYIMBg///xRDn//OoIMBcYISBBgUHNATpCgjCngIEDFIM+AoV8TYKYCMIJQBAQLCCgZcBYQIJBX4UHCwSJBYQaSCMYQDCYQabEBgngW4V4WoQBBOgIMN+AoCEwY+BGYZfBYwQIBv+AG4X+j/8K4TCB+bECM4P+YgcD//B/67Ch/4h//K4SSBv5IBAAdAWqMYAokDD4t+AokfBgi0DAAX/Bgkf7wSE/IME/6PBCQfBBgcD/AME/ypCCQXABgYSBBgg+BBgYSBBgatBBggSBBgYSBBgcB/4ACZ4QGDZ4IMLFARAEAAJaEBjQAUhAnFMgIABuD5CVwWAboUDLwZ0DNYKLBM4IMBh50C55rBCoWACAIMC+EPFIN4EQQMBg4MSHgYzEBgIzBIAUAvhND+EH8DZCBAN/bIfwMQP/OgIMBLgalCBgKlDg//V4kfCQIAqWgYzC/gFDIAJgBZoS3CAwV//4TDh/+j5UCCQOAn4SD8DPCCQSbCCQR/BNAV/3i1CB4PzAYLCBgP8AYIMCv+HBgcP+AMDCQMHEwb2BYQLPDgYMBIAKoBOYLPCwDNBZ4UQBQPhJ4J0EDYJbCZ4R7EAoZiDSoaUDADBNBFQj5EKwQMEGAoMEOgQFCnAMEQIYFBgaOCBgTRBBgc/AYIMCaIQMCgb2CBgX/JQIMCDAQMCh/8JoYYBJoiNDBgIYDBgIYDBgPzUwkfUwisBOokfDAYMCQIq/ERwwAcn4pCgfwg42D//B/6hBCAP+KwYQBMQKbBgF//9+g5EBh4YB4CfC/EHDwK1Dn7PD8A0BgF4gEeAIUHBgQBBBi4mEGYpAEAIMP4BNELQpnGOgM/ZYaBFGQMPYos/JAIAuj4xEKgJrBfoX//hEE/4TDCQJSCCoN/gZfBjCBCj+AgaOCAIiKBg4OCgKKBvgbCWYMDToK1CgE8JIQMC4ZCBBgU4HYTNCz4JBEwV7KoQzCUIYvBLYZNBn60CLQPfCQcDM4LHCEALHDZ4TaCCYaODHYK8fh6FDEwKSCF4Uf4COCBgJsBn4MDDIJPDVgYAZA='))), + 46, + atob("CxMeHh4eHh4eHh4eDQ=="), + 52+(scale<<8)+(1<<16) + ); + return this; +}; + +Graphics.prototype.setFontLatoSmall = function(scale) { + // Actual height 21 (20 - 0) + this.setFontCustom( + E.toString(require('heatshrink').decompress(atob('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'))), + 32, + atob("BAcIDAwRDwUGBggMBAcECAwMDAwMDAwMDAwFBQwMDAgRDg4OEAwMDxAGCQ4LExARDREOCwwPDhUODQ0GCAYMCAYLDAoMCwcLDAUFCwURDAwMDAgJCAwLEAsLCgYGBgwA"), + 21+(scale<<8)+(1<<16) + ); + return this; +}; + +// creates a list of prime factors of n and outputs them as a string, if n is prime outputs "Prime Time!" +function primeFactors(n) { + const factors = []; + let divisor = 2; + + while (n >= 2) { + if (n % divisor == 0) { + factors.push(divisor); + n = n / divisor; + } else { + divisor++; + } + } + if (factors.length === 1) { + return "Prime Time!"; + } + else + return factors.toString(); +} + + +// converts time HR:MIN to integer HRMIN e.g. 15:35 => 1535 +function timeToInt(t) { + var arr = t.split(':'); + var intTime = parseInt(arr[0])*100+parseInt(arr[1]); + + return intTime; +} + +function draw() { + var date = new Date(); + var timeStr = require("locale").time(date,1); + var primeStr = primeFactors(timeToInt(timeStr)); + + g.reset(); + g.setColor(0,0,0); + g.fillRect(Bangle.appRect); + + //g.setFont("6x8", w/30); + g.setFontLato(); + g.setFontAlign(0, 0); + g.setColor(100,100,100); + g.drawString(timeStr, w/2, h/2); + + //g.setFont("6x8", w/60); + g.setFontLatoSmall(); + g.drawString(primeStr, w/2, 3*h/4); + queueDraw(); +} + +// timeout used to update every minute +var drawTimeout; + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); +} + +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); + + +g.clear(); +// Show launcher when middle button pressed +Bangle.setUI("clock"); + +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); +draw(); diff --git a/apps/primetimelato/app.png b/apps/primetimelato/app.png new file mode 100644 index 0000000000000000000000000000000000000000..2a84c62a07e71744a3721a4a7f8e3caa3721d71c GIT binary patch literal 710 zcmV;%0y+JOP)Px%fJsC_R9Hvtm^+TbFc5|(bXUD~@YEpQpp&!1vedHBEsjPT^cG zM;ybcdbe!c0b3UI$(&QzDXb~rLc)cF3yHL2;5Q1RAQ}#bY@%AN((!nFiCZidxfVfv zq8@m6zu)su!T0{Zv>2;NWb5I8d`y=R4S}elv5oT zp@7cHvoaD^fhBfzqXILTObFX76JR{ETrNp=IeN$>g@uvANx-k1=n7-f;;h%}JSysL zCJB~1XHvi?g~U6+dIzBR{eF)eohZ9Tz)=(9)udA$MNK+2bW#IGKE=$J^n=tSX-$t| zbzi6hOL`P&gasz8WR#?^Fjg3b;uemmED^O32&9AUmcGzol?iP_O(r z;Iv2Ke=3Yr)#-G?>I~TgUpu8*)7!rp1#1eQPN#>@ut-yCZq?hLLR$ewZGe(d77XNN zwYb;YpTZi~5=joEw%u;GwApOJ599iWa%m^o%Pg&_OR|)WrYo3fC#-~osWThTIba(q sW){O~!&=J{S%8WU7sF|*{dEfe0H(cp6H7fzivR!s07*qoM6N<$f*j~OtpET3 literal 0 HcmV?d00001 diff --git a/apps/primetimelato/icon.js b/apps/primetimelato/icon.js new file mode 100644 index 000000000..06f93e2ef --- /dev/null +++ b/apps/primetimelato/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwIdah/wAof//4ECgYFB4AFBg4FB8AFBj/wh/4AoM/wEB/gFBvwCEBAU/AQP4gfAj8AgPwAoMPwED8AFBg/AAYIBDA4ngg4TB4EBApkPKgJSBJQIFTMgIFCJIIFDKoIFEvgFBGoMAnw7DP4IFEh+BAoItBg+DNIQwBMIaeCKoKxCPoIzCEgKVHUIqtFXIrFFaIrdFdIwAV")) diff --git a/apps/primetimelato/metadata.json b/apps/primetimelato/metadata.json new file mode 100644 index 000000000..ab30724ba --- /dev/null +++ b/apps/primetimelato/metadata.json @@ -0,0 +1,15 @@ +{ "id": "primetime", + "name": "Prime Time Lato Clock", + "version": "0.01", + "type": "clock", + "description": "A clock that tells you the primes of the time in the Lato font", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "tags": "clock", + "supports": ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"primetimelato.app.js","url":"app.js"}, + {"name":"primetimelato.img","url":"icon.js","evaluate":true} + ] +} diff --git a/apps/primetimelato/screenshot.png b/apps/primetimelato/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..7f6e7cc0d173c5b79feb938a18255d874f9359cc GIT binary patch literal 2287 zcmeHJX*3)79{nc~QA_bG)1c8|rnc5ndzIpd&}xy!5~(ngaZIbqYsMB^MyaKkE*MiK zGc;6-L~E-hQcYV`RCr>kiL}O+sH8NhSn7G_ypQkG`}ofL@cZ3!&%K}S`JH=y`2lA! zYRY=b001>#A1~}4GXFJ7ihG;U{ugl%AY?4Y6EqDQECZla@9X7(OD2A(iLt^)+4 zvcPRC>h5+5D!;ck!c5jns;t}KwT3zOd`v9$!i5Mj0YQQq3e%uXEax;Qs6BLeSS$1n z-0gw31HuTNL9>c_PK=0qIy=oRt$?pj1RYWpSoruGbF_X+V&HF>&kc0yE(ixHb)Rsl z?Z|7ewDUhGvU|FoV2)gQscotvX$_AFS(&zC3zpln3N_)QVEd=z zzZ=w{hu8zF4>*P89%p-@wh-3bYIJtTTeVpTv$e)tJ-bk2=f=<=5RCb~Rbkry`o^xf zbvNjc8hbGXn=&bM&Iwo~CG2nG!J0msF?HBU>fwzkZE&-7@sv2IJNrpnv%CQFz0d!Ldg9V~wik zuh5VvyHEEO*eGfLnR?KREg97{lhc}0)k78Ea^~i_y6L54&mof zV3CR3SylIX_*2{xzEBU3Dp3fvnV(L!J5a{ti5gMW!t)-+r=LxT<^jrPLBmLS zKYFsRybjfEPxDCf*RD$q_3mrQMPU$u;nf^}8J{aU5)3-NTXXR%V)>4bsf&JdhiB@RxQd_>PtabxK%w4O zurlUk4nHta;4XNJ+0g;C#5vuOfevn}?O<^?%S+jSlWRv?~pGlHX6qd{2%9Zu|< z0(8^-&yP&LqJE_iiq!9>;biU(wr$#MK6&zziyz0#i=)SrH!of*-xnuTKNdzaPvIy; z>ensl_pz$2j6Uq&wxqf`X8UiJN0=2TT2fpY-oY8pR9BLh1KCKJA9_`@uk(xn1A{Dy zP0OR?=8rBiO)0LqQtU-)us&+Q1~qFUN2pzeCf=@j9@a z|8^9%qLZl2=bpgJU(Kp;w=AW_8L2ISq|;zq;UjlRYWH+Y{>4SLXxjN`IwiBYgls8utH{dTL+#Kr<%-j6cnIR54mF`+ACH6*RQ24Go z8NQhgsrpt~#0vyeQ8JqDs0^$_OM(IQ^jpkFpbGnU`JVvK+%LdEM@zc4I@>xR3<4}; z4WGlTRsS37OeA}YZcH1Vg~tNc->26b-FR_Egx(#|&@6nW#vibpG8C6o38GyFyM?7H z373QJ3aA>D_Qm@5wQv$`V0OqYQJ_yHP$|6^rDJl7J~j5iref&*V)aIBxBTGIG8K3v z_mO5^b?==43eYCt%~h#z7mUEQ4F0`GBt{9Sye}%=FWi?C(C6=iJ1CTzb0Exj*l+Ck zt=)1R>Pn*~)lgdme^Ef&p)lkY9GIl&dW|ikv<|v$e&Lfr3fwf60t7D*$fJ3~?~>eQ zX@6TB65CM5LqP`Uh}vv+afAFg--a64z~`|DYE*v;UUHY7?$NN)HenEhIC(X_^%hw$ z8xM=0Rok`Lgf}CO#IYW4uPuWW<_N{~ahYs^AQDTC1DEr%)hd1(X8H9!sN`7i>XZ@? iFK- Date: Sat, 5 Nov 2022 00:33:00 +0000 Subject: [PATCH 085/179] Added PrimeTimeLato app --- apps/primetimelato/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/primetimelato/metadata.json b/apps/primetimelato/metadata.json index ab30724ba..88beed6ac 100644 --- a/apps/primetimelato/metadata.json +++ b/apps/primetimelato/metadata.json @@ -1,4 +1,4 @@ -{ "id": "primetime", +{ "id": "primetimelato", "name": "Prime Time Lato Clock", "version": "0.01", "type": "clock", From 91f0564c0d1e0fa55f397b37bb4d577b734f75f1 Mon Sep 17 00:00:00 2001 From: hugh Date: Sat, 5 Nov 2022 00:45:13 +0000 Subject: [PATCH 086/179] Added PrimeTimeLato app --- apps/primetimelato/ChangeLog | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/primetimelato/ChangeLog diff --git a/apps/primetimelato/ChangeLog b/apps/primetimelato/ChangeLog new file mode 100644 index 000000000..9db0e26c5 --- /dev/null +++ b/apps/primetimelato/ChangeLog @@ -0,0 +1 @@ +0.01: first release From a79b130e887b7867960d8cee5c60eba7c9d00ea7 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Fri, 4 Nov 2022 18:34:15 +0100 Subject: [PATCH 087/179] powermanager - New option to automatically calibrate the battery --- apps/powermanager/ChangeLog | 2 ++ apps/powermanager/README.md | 3 ++- apps/powermanager/boot.js | 9 +++++++ apps/powermanager/lib.js | 6 +++++ apps/powermanager/metadata.json | 3 ++- apps/powermanager/settings.js | 47 +++++++++++---------------------- 6 files changed, 36 insertions(+), 34 deletions(-) create mode 100644 apps/powermanager/lib.js diff --git a/apps/powermanager/ChangeLog b/apps/powermanager/ChangeLog index f0b60a45a..a83e8c676 100644 --- a/apps/powermanager/ChangeLog +++ b/apps/powermanager/ChangeLog @@ -1,3 +1,5 @@ 0.01: New App! 0.02: Allow forcing monotonic battery voltage/percentage 0.03: Use default Bangle formatter for booleans +0.04: Remove calibration with current voltage (Calibrate->Auto) as it is now handled by settings app + Allow automatic calibration on every charge longer than 3 hours diff --git a/apps/powermanager/README.md b/apps/powermanager/README.md index 434ec814e..88b3c370a 100644 --- a/apps/powermanager/README.md +++ b/apps/powermanager/README.md @@ -3,8 +3,9 @@ Manages settings for charging. Features: * Warning threshold to be able to disconnect the charger at a given percentage -* Set the battery calibration offset. +* Set the battery calibration offset * Force monotonic battery percentage or voltage +* Automatic calibration on charging uninterrupted longer than 3 hours (reloads of the watch reset the timer). ## Internals diff --git a/apps/powermanager/boot.js b/apps/powermanager/boot.js index 077e24413..3ddaad8e0 100644 --- a/apps/powermanager/boot.js +++ b/apps/powermanager/boot.js @@ -48,4 +48,13 @@ return v; }; } + + if (settings.autoCalibration){ + let chargeStart; + Bangle.on("charging", (charging)=>{ + if (charging) chargeStart = Date.now(); + if (chargeStart && !charging && (Date.now() - chargeStart > 1000*60*60*3)) require("powermanager").setCalibration(); + if (!charging) chargeStart = undefined; + }); + } })(); diff --git a/apps/powermanager/lib.js b/apps/powermanager/lib.js new file mode 100644 index 000000000..f4a7e3378 --- /dev/null +++ b/apps/powermanager/lib.js @@ -0,0 +1,6 @@ +// set battery calibration value by either applying the given value or setting the currently read battery voltage +exports.setCalibration = function(calibration){ + let s = require('Storage').readJSON("setting.json", true) || {}; + s.batFullVoltage = calibration?calibration:((analogRead(D3) + analogRead(D3) + analogRead(D3) + analogRead(D3)) / 4); + require('Storage').writeJSON("setting.json", s); +} diff --git a/apps/powermanager/metadata.json b/apps/powermanager/metadata.json index dd1727657..0777feee3 100644 --- a/apps/powermanager/metadata.json +++ b/apps/powermanager/metadata.json @@ -2,7 +2,7 @@ "id": "powermanager", "name": "Power Manager", "shortName": "Power Manager", - "version": "0.03", + "version": "0.04", "description": "Allow configuration of warnings and thresholds for battery charging and display.", "icon": "app.png", "type": "bootloader", @@ -12,6 +12,7 @@ "storage": [ {"name":"powermanager.boot.js","url":"boot.js"}, {"name":"powermanager.settings.js","url":"settings.js"}, + {"name":"powermanager","url":"lib.js"}, {"name":"powermanager.default.json","url":"default.json"} ] } diff --git a/apps/powermanager/settings.js b/apps/powermanager/settings.js index 7cc683024..9eeb29e00 100644 --- a/apps/powermanager/settings.js +++ b/apps/powermanager/settings.js @@ -23,7 +23,6 @@ '': { 'title': 'Power Manager' }, - '< Back': back, 'Monotonic percentage': { value: !!settings.forceMonoPercentage, onchange: v => { @@ -44,29 +43,29 @@ } }; - function roundToDigits(number, stepsize) { return Math.round(number / stepsize) * stepsize; } - function getCurrentVoltageDirect() { - return (analogRead(D3) + analogRead(D3) + analogRead(D3) + analogRead(D3)) / 4; - } - var stepsize = 0.0002; - var full = 0.32; + var full = 0.3144; function getInitialCalibrationOffset() { return roundToDigits(systemsettings.batFullVoltage - full, stepsize) || 0; } - var submenu_calibrate = { '': { - title: "Calibrate" + title: "Calibrate", + back: function() { + E.showMenu(mainmenu); + }, }, - '< Back': function() { - E.showMenu(mainmenu); + 'Autodetect': { + value: !!settings.autoCalibration, + onchange: v => { + writeSettings("autoCalibration", v); + } }, 'Offset': { min: -0.05, @@ -75,25 +74,9 @@ value: getInitialCalibrationOffset(), format: v => roundToDigits(v, stepsize).toFixed((""+stepsize).length - 2), onchange: v => { - print(typeof v); - systemsettings.batFullVoltage = v + full; - require("Storage").writeJSON("setting.json", systemsettings); + require("powermanager").setCalibration(v + full); } }, - 'Auto': function() { - var newVoltage = getCurrentVoltageDirect(); - E.showAlert("Please charge fully before auto setting").then(() => { - E.showPrompt("Set current charge as full").then((r) => { - if (r) { - systemsettings.batFullVoltage = newVoltage; - require("Storage").writeJSON("setting.json", systemsettings); - //reset value shown in menu to the newly set one - submenu_calibrate.Offset.value = getInitialCalibrationOffset(); - E.showMenu(mainmenu); - } - }); - }); - }, 'Clear': function() { E.showPrompt("Clear charging offset?").then((r) => { if (r) { @@ -109,10 +92,10 @@ var submenu_chargewarn = { '': { - title: "Charge warning" - }, - '< Back': function() { - E.showMenu(mainmenu); + title: "Charge warning", + back: function() { + E.showMenu(mainmenu); + }, }, 'Enabled': { value: !!settings.warnEnabled, From bf135ba54ce448a9a9d0f2bfb10e6e4205c559d8 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sat, 5 Nov 2022 10:06:04 +0100 Subject: [PATCH 088/179] powermanager - Remove print --- apps/powermanager/boot.js | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/powermanager/boot.js b/apps/powermanager/boot.js index 3ddaad8e0..2bc2aaa35 100644 --- a/apps/powermanager/boot.js +++ b/apps/powermanager/boot.js @@ -5,7 +5,6 @@ ); if (settings.warnEnabled){ - print("Charge warning enabled"); var chargingInterval; function handleCharging(charging){ From 6687986dab82d30b184a8f1f72d27fcbe0296d87 Mon Sep 17 00:00:00 2001 From: hugh Date: Sat, 5 Nov 2022 15:07:04 +0000 Subject: [PATCH 089/179] added option to buzz on prime, with settings --- apps/primetimelato/app.js | 31 ++++++++++++++++++++++++++--- apps/primetimelato/metadata.json | 7 +++++-- apps/primetimelato/settings.js | 34 ++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 apps/primetimelato/settings.js diff --git a/apps/primetimelato/app.js b/apps/primetimelato/app.js index 2031fd53b..e03e8fa51 100644 --- a/apps/primetimelato/app.js +++ b/apps/primetimelato/app.js @@ -1,5 +1,7 @@ const h = g.getHeight(); const w = g.getWidth(); +const SETTINGS_FILE = "pastel.json"; +let settings; Graphics.prototype.setFontLato = function(scale) { // Actual height 41 (43 - 3) @@ -22,6 +24,11 @@ Graphics.prototype.setFontLatoSmall = function(scale) { ); return this; }; + +function loadSettings() { + settings = require("Storage").readJSON(SETTINGS_FILE,1)||{}; + settings.buzz_on_prime = (settings.buzz_on_prime === undefined ? false : settings.buzz_on_prime); +} // creates a list of prime factors of n and outputs them as a string, if n is prime outputs "Prime Time!" function primeFactors(n) { @@ -55,24 +62,41 @@ function timeToInt(t) { function draw() { var date = new Date(); var timeStr = require("locale").time(date,1); - var primeStr = primeFactors(timeToInt(timeStr)); + var intTime = timeToInt(timeStr); + var primeStr = primeFactors(intTime); g.reset(); g.setColor(0,0,0); g.fillRect(Bangle.appRect); - //g.setFont("6x8", w/30); g.setFontLato(); g.setFontAlign(0, 0); g.setColor(100,100,100); g.drawString(timeStr, w/2, h/2); - //g.setFont("6x8", w/60); g.setFontLatoSmall(); g.drawString(primeStr, w/2, 3*h/4); + // Buzz if Prime Time and between 8am and 8pm + if (settings.buzz_on_prime && primeStr == "Prime Time!" && intTime >= 800 && intTime <= 2000) + buzzer(2); queueDraw(); } +// timeout for multi-buzzer +var buzzTimeout; + +// n buzzes +function buzzer(n) { + if (n-- < 1) return; + Bangle.buzz(250); + + if (buzzTimeout) clearTimeout(buzzTimeout); + buzzTimeout = setTimeout(function() { + buzzTimeout = undefined; + buzzer(n); + }, 500); +} + // timeout used to update every minute var drawTimeout; @@ -96,6 +120,7 @@ Bangle.on('lcdPower',on=>{ }); +loadSettings(); g.clear(); // Show launcher when middle button pressed Bangle.setUI("clock"); diff --git a/apps/primetimelato/metadata.json b/apps/primetimelato/metadata.json index 88beed6ac..eaecf94f5 100644 --- a/apps/primetimelato/metadata.json +++ b/apps/primetimelato/metadata.json @@ -10,6 +10,9 @@ "readme": "README.md", "storage": [ {"name":"primetimelato.app.js","url":"app.js"}, - {"name":"primetimelato.img","url":"icon.js","evaluate":true} - ] + {"name":"primetimelato.img","url":"icon.js","evaluate":true}, + {"name":"primetimelato.settings.js","url":"settings.js"} + + ], + "data": [{"name":"primetimelato.json"}] } diff --git a/apps/primetimelato/settings.js b/apps/primetimelato/settings.js new file mode 100644 index 000000000..19702ed84 --- /dev/null +++ b/apps/primetimelato/settings.js @@ -0,0 +1,34 @@ +(function(back) { + const SETTINGS_FILE = "primetimelato.json"; + + // initialize with default settings... + let s = { + 'buzz_on_prime': true, + } + + // ...and overwrite them with any saved values + // This way saved values are preserved if a new version adds more settings + const storage = require('Storage') + let settings = storage.readJSON(SETTINGS_FILE, 1) || {} + const saved = settings || {} + for (const key in saved) { + s[key] = saved[key] + } + + function save() { + settings = s + storage.write(SETTINGS_FILE, settings) + } + + E.showMenu({ + '': { 'title': 'Prime Time Lato' }, + '< Back': back, + 'Buzz on Prime': { + value: !!s.buzz_on_prime, + onchange: v => { + s.buzz_on_prime = v; + save(); + }, + } + }) +}) From dbc325748d2ae0d8b78ef742b9d40fda68101e41 Mon Sep 17 00:00:00 2001 From: Hugh Barney Date: Sat, 5 Nov 2022 15:10:04 +0000 Subject: [PATCH 090/179] added option to buzz on prime, with settings --- apps/primetimelato/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/primetimelato/ChangeLog b/apps/primetimelato/ChangeLog index 9db0e26c5..46690e360 100644 --- a/apps/primetimelato/ChangeLog +++ b/apps/primetimelato/ChangeLog @@ -1 +1,2 @@ 0.01: first release +0.02: added option to buzz on prime, with settings From 409cba80b9ec036c070a513fa4b343395a6a2a4a Mon Sep 17 00:00:00 2001 From: Hugh Barney Date: Sat, 5 Nov 2022 15:20:31 +0000 Subject: [PATCH 091/179] added option to buzz on prime, with settings --- apps/primetimelato/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/primetimelato/metadata.json b/apps/primetimelato/metadata.json index eaecf94f5..6b292c380 100644 --- a/apps/primetimelato/metadata.json +++ b/apps/primetimelato/metadata.json @@ -1,6 +1,6 @@ { "id": "primetimelato", "name": "Prime Time Lato Clock", - "version": "0.01", + "version": "0.02", "type": "clock", "description": "A clock that tells you the primes of the time in the Lato font", "icon": "app.png", From 453895c134ed70b346f944dbe0dd05f32e0f4624 Mon Sep 17 00:00:00 2001 From: Hugh Barney Date: Sat, 5 Nov 2022 15:52:38 +0000 Subject: [PATCH 092/179] added option to buzz on prime, with settings --- apps/primetimelato/README.md | 6 ++++++ apps/primetimelato/app.js | 1 + 2 files changed, 7 insertions(+) diff --git a/apps/primetimelato/README.md b/apps/primetimelato/README.md index 6760fe41a..924a6fae6 100644 --- a/apps/primetimelato/README.md +++ b/apps/primetimelato/README.md @@ -4,6 +4,12 @@ A watchface that displays time and its prime factors in the Lato font. For example when the time is 21:05, the prime factors are 5,421. Displays 'Prime Time!' when the time is a prime number. +There is a settings option added in the Settings App. If 'Buzz on +Prime' is ticked then the buzzer will sound when 'Prime Time!' is +detected. Note the buzzer is limited to between 8am and 8pm so it +should not go off when you want to sleep. + + ![](screenshot.jpg) Written by: [Hugh Barney](https://github.com/hughbarney) diff --git a/apps/primetimelato/app.js b/apps/primetimelato/app.js index e03e8fa51..5cbc68cfe 100644 --- a/apps/primetimelato/app.js +++ b/apps/primetimelato/app.js @@ -76,6 +76,7 @@ function draw() { g.setFontLatoSmall(); g.drawString(primeStr, w/2, 3*h/4); + // Buzz if Prime Time and between 8am and 8pm if (settings.buzz_on_prime && primeStr == "Prime Time!" && intTime >= 800 && intTime <= 2000) buzzer(2); From c54dde90ea899bf6bae97f927da0d5dd13e0f081 Mon Sep 17 00:00:00 2001 From: Hugh Barney Date: Sat, 5 Nov 2022 17:52:29 +0000 Subject: [PATCH 093/179] added option to buzz on prime, with settings --- apps/primetimelato/app.js | 2 +- apps/primetimelato/settings.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/primetimelato/app.js b/apps/primetimelato/app.js index 5cbc68cfe..817da7cda 100644 --- a/apps/primetimelato/app.js +++ b/apps/primetimelato/app.js @@ -1,6 +1,6 @@ const h = g.getHeight(); const w = g.getWidth(); -const SETTINGS_FILE = "pastel.json"; +const SETTINGS_FILE = "primetimelato.json"; let settings; Graphics.prototype.setFontLato = function(scale) { diff --git a/apps/primetimelato/settings.js b/apps/primetimelato/settings.js index 19702ed84..5550055eb 100644 --- a/apps/primetimelato/settings.js +++ b/apps/primetimelato/settings.js @@ -3,7 +3,7 @@ // initialize with default settings... let s = { - 'buzz_on_prime': true, + 'buzz_on_prime': true } // ...and overwrite them with any saved values @@ -16,8 +16,8 @@ } function save() { - settings = s - storage.write(SETTINGS_FILE, settings) + settings = s; + storage.write(SETTINGS_FILE, settings); } E.showMenu({ From 80ed8c919260641b4bbc10677aa587859c37a090 Mon Sep 17 00:00:00 2001 From: Marco H Date: Sat, 5 Nov 2022 20:39:51 +0100 Subject: [PATCH 094/179] Write AGPS data chunks with delay to improve reliability --- apps/agpsdata/ChangeLog | 1 + apps/agpsdata/app.js | 2 +- apps/agpsdata/lib.js | 104 +++++++++++++++++++++--------------- apps/agpsdata/metadata.json | 2 +- 4 files changed, 64 insertions(+), 45 deletions(-) diff --git a/apps/agpsdata/ChangeLog b/apps/agpsdata/ChangeLog index 89844a132..8ada244d7 100644 --- a/apps/agpsdata/ChangeLog +++ b/apps/agpsdata/ChangeLog @@ -2,3 +2,4 @@ 0.02: Load AGPS data on app start and automatically in background 0.03: Do not load AGPS data on boot Increase minimum interval to 6 hours +0.04: Write AGPS data chunks with delay to improve reliability diff --git a/apps/agpsdata/app.js b/apps/agpsdata/app.js index 647723bb4..4a6d2ba5c 100644 --- a/apps/agpsdata/app.js +++ b/apps/agpsdata/app.js @@ -36,7 +36,7 @@ function updateAgps() { g.clear(); if (!waiting) { waiting = true; - display("Updating A-GPS..."); + display("Updating A-GPS...", "takes ~ 10 seconds"); require("agpsdata").pull(function() { waiting = false; display("A-GPS updated.", "touch to close"); diff --git a/apps/agpsdata/lib.js b/apps/agpsdata/lib.js index 7d9758c0a..34608a5c6 100644 --- a/apps/agpsdata/lib.js +++ b/apps/agpsdata/lib.js @@ -8,41 +8,52 @@ var FILE = "agpsdata.settings.json"; var settings; readSettings(); -function setAGPS(data) { - var js = jsFromBase64(data); - try { - eval(js); - return true; - } - catch(e) { - console.log("error:", e); - } - return false; +function setAGPS(b64) { + return new Promise(function(resolve, reject) { + var initCommands = "Bangle.setGPSPower(1);\n"; // turn GPS on + const gnsstype = settings.gnsstype || 1; // default GPS + initCommands += `Serial1.println("${CASIC_CHECKSUM("$PCAS04," + gnsstype)}")\n`; // set GNSS mode + // What about: + // NAV-TIMEUTC (0x01 0x10) + // NAV-PV (0x01 0x03) + // or AGPS.zip uses AID-INI (0x0B 0x01) + + eval(initCommands); + + try { + writeChunks(atob(b64), resolve); + } catch (e) { + console.log("error:", e); + reject(); + } + }); } -function jsFromBase64(b64) { - var bin = atob(b64); - var chunkSize = 128; - var js = "Bangle.setGPSPower(1);\n"; // turn GPS on - var gnsstype = settings.gnsstype || 1; // default GPS - js += `Serial1.println("${CASIC_CHECKSUM("$PCAS04,"+gnsstype)}")\n`; // set GNSS mode - // What about: - // NAV-TIMEUTC (0x01 0x10) - // NAV-PV (0x01 0x03) - // or AGPS.zip uses AID-INI (0x0B 0x01) +var chunkI = 0; +function writeChunks(bin, resolve) { + return new Promise(function(resolve2) { + const chunkSize = 128; + setTimeout(function() { + if (chunkI < bin.length) { + var chunk = bin.substr(chunkI, chunkSize); + js = `Serial1.write(atob("${btoa(chunk)}"))\n`; + eval(js); - for (var i=0;i { - let result = setAGPS(event.resp); - if (result) { - updateLastUpdate(); - if (successCallback) successCallback(); - } else { - console.log("error applying AGPS data"); - if (failureCallback) failureCallback("Error applying AGPS data"); - } - }).catch((e)=>{ - console.log("error", e); - if (failureCallback) failureCallback(e); - }); + const uri = "https://www.espruino.com/agps/casic.base64"; + if (Bangle.http) { + Bangle.http(uri, {timeout : 10000}) + .then(event => { + setAGPS(event.resp) + .then(r => { + updateLastUpdate(); + if (successCallback) + successCallback(); + }) + .catch((e) => { + console.log("error", e); + if (failureCallback) + failureCallback(e); + }); + }) + .catch((e) => { + console.log("error", e); + if (failureCallback) + failureCallback(e); + }); } else { console.log("error: No http method found"); - if (failureCallback) failureCallback(/*LANG*/"No http method"); + if (failureCallback) + failureCallback(/*LANG*/ "No http method"); } }; diff --git a/apps/agpsdata/metadata.json b/apps/agpsdata/metadata.json index 1ce299532..203a00f72 100644 --- a/apps/agpsdata/metadata.json +++ b/apps/agpsdata/metadata.json @@ -2,7 +2,7 @@ "name": "A-GPS Data Downloader App", "shortName":"A-GPS Data", "icon": "agpsdata.png", - "version":"0.03", + "version":"0.04", "description": "Once installed, this app allows you to download assisted GPS (A-GPS) data directly to your Bangle.js **via Gadgetbridge on an Android phone** when you run the app. If you just want to upload the latest AGPS data from this app loader, please use the `Assisted GPS Update (AGPS)` app.", "tags": "boot,tool,assisted,gps,agps,http", "allow_emulator":true, From b4b3775b23a90003011bbdcdf71e0572599bda0d Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Sun, 6 Nov 2022 00:48:38 +0100 Subject: [PATCH 095/179] exit by pressing upper left corner --- apps/torch/ChangeLog | 1 + apps/torch/README.md | 2 ++ apps/torch/app.js | 6 ++++++ apps/torch/metadata.json | 2 +- 4 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 apps/torch/README.md diff --git a/apps/torch/ChangeLog b/apps/torch/ChangeLog index fd904b6e8..22b1c179a 100644 --- a/apps/torch/ChangeLog +++ b/apps/torch/ChangeLog @@ -3,3 +3,4 @@ 0.03: Add Color Changing Settings 0.04: Add Support For Bangle.js 2 0.05: Default full Brightness +0.06: Press upper left corner to exit on Bangle.js 2 diff --git a/apps/torch/README.md b/apps/torch/README.md new file mode 100644 index 000000000..e06861071 --- /dev/null +++ b/apps/torch/README.md @@ -0,0 +1,2 @@ +On Bangle.js 2, pressing the upper left corner where the red back button would be exits the app if the screen is unlocked. + diff --git a/apps/torch/app.js b/apps/torch/app.js index 2af35fdb6..78eda214b 100644 --- a/apps/torch/app.js +++ b/apps/torch/app.js @@ -13,8 +13,14 @@ Bangle.setLCDTimeout(0); g.reset(); g.setColor(settings.bg); g.fillRect(0,0,g.getWidth(),g.getHeight()); + // Any button turns off setWatch(()=>load(), BTN1); if (global.BTN2) setWatch(()=>load(), BTN2); if (global.BTN3) setWatch(()=>load(), BTN3); +// Press upper left corner to exit (where red back button would be) +Bangle.setUI({ + mode : 'custom', + back : load +}); diff --git a/apps/torch/metadata.json b/apps/torch/metadata.json index af85370ac..580ae4e8a 100644 --- a/apps/torch/metadata.json +++ b/apps/torch/metadata.json @@ -2,7 +2,7 @@ "id": "torch", "name": "Torch", "shortName": "Torch", - "version": "0.05", + "version": "0.06", "description": "Turns screen white to help you see in the dark. Select from the launcher or press BTN1,BTN3,BTN1,BTN3 quickly to start when in any app that shows widgets on Bangle.js 1. You can also set the color through the app's setting menu.", "icon": "app.png", "tags": "tool,torch", From ad88625b8c4e54b36e2045b148a4e7084d769fda Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 30 Oct 2022 10:54:23 +0100 Subject: [PATCH 096/179] imageclock - Use widget_utils module --- apps/imageclock/app.js | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/apps/imageclock/app.js b/apps/imageclock/app.js index ff3f5a62d..a0f1e6a74 100644 --- a/apps/imageclock/app.js +++ b/apps/imageclock/app.js @@ -604,12 +604,8 @@ let firstDraw = true; promise.then(()=>{ let currentDrawingTime = Date.now(); - if (showWidgets && global.WIDGETS){ - //print("Draw widgets"); + if (showWidgets){ restoreWidgetDraw(); - Bangle.drawWidgets(); - g.setColor(g.theme.fg); - g.drawLine(0,24,g.getWidth(),24); } lastDrawTime = Date.now() - start; isDrawing=false; @@ -754,13 +750,8 @@ let firstDraw = true; let currentDragDistance = 0; let restoreWidgetDraw = function(){ - if (global.WIDGETS) { - for (let w in global.WIDGETS) { - let wd = global.WIDGETS[w]; - wd.draw = originalWidgetDraw[w]; - wd.area = originalWidgetArea[w]; - } - } + require("widget_utils").show(); + Bangle.drawWidgets(); }; let handleDrag = function(e){ @@ -814,17 +805,7 @@ let firstDraw = true; let clearWidgetsDraw = function(){ //print("Clear widget draw calls"); - if (global.WIDGETS) { - originalWidgetDraw = {}; - originalWidgetArea = {}; - for (let w in global.WIDGETS) { - let wd = global.WIDGETS[w]; - originalWidgetDraw[w] = wd.draw; - originalWidgetArea[w] = wd.area; - wd.draw = () => {}; - wd.area = ""; - } - } + require("widget_utils").hide(); } handleLock(Bangle.isLocked(), true); From 866155bbd053088f1f5bfd70c70945d9f4e6798a Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 30 Oct 2022 21:56:24 +0100 Subject: [PATCH 097/179] imageclock - Directly set cached resource --- apps/imageclock/app.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/apps/imageclock/app.js b/apps/imageclock/app.js index a0f1e6a74..0f34457cf 100644 --- a/apps/imageclock/app.js +++ b/apps/imageclock/app.js @@ -292,14 +292,7 @@ let firstDraw = true; if (resource){ prepareImg(resource); //print("lastElem", typeof resource) - if (resource) { - element.cachedImage[cacheKey] = resource; - //print("cache res ",typeof element.cachedImage[cacheKey]); - } else { - element.cachedImage[cacheKey] = null; - //print("cache null",typeof element.cachedImage[cacheKey]); - //print("Could not create image from", resource); - } + element.cachedImage[cacheKey] = resource; } else { //print("Could not get resource from", element, lastElem); } From 94df58412b207f3da3a540a7ffb302c927aa3cc9 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 30 Oct 2022 22:12:38 +0100 Subject: [PATCH 098/179] imageclock - Cache searches for numerical images --- apps/imageclock/app.js | 44 +++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/apps/imageclock/app.js b/apps/imageclock/app.js index 0f34457cf..7cbd9f008 100644 --- a/apps/imageclock/app.js +++ b/apps/imageclock/app.js @@ -202,27 +202,39 @@ let firstDraw = true; let firstDigitY = element.Y; let imageIndex = element.ImageIndex ? element.ImageIndex : 0; - let firstImage; - if (imageIndex){ - firstImage = getByPath(resources, [], "" + (0 + imageIndex)); - } else { - firstImage = getByPath(resources, element.ImagePath, 0); + let firstImage = element.cachedFirstImage; + if (!firstImage && !element.cachedFirstImageMissing){ + if (imageIndex){ + firstImage = getByPath(resources, [], "" + (0 + imageIndex)); + } else { + firstImage = getByPath(resources, element.ImagePath, 0); + } + element.cachedFirstImage = firstImage; + if (!firstImage) element.cachedFirstImageMissing = true; } - let minusImage; - if (imageIndexMinus){ - minusImage = getByPath(resources, [], "" + (0 + imageIndexMinus)); - } else { - minusImage = getByPath(resources, element.ImagePath, "minus"); + let minusImage = element.cachedMinusImage; + if (!minusImage && !element.cachedMinusImageMissing){ + if (imageIndexMinus){ + minusImage = getByPath(resources, [], "" + (0 + imageIndexMinus)); + } else { + minusImage = getByPath(resources, element.ImagePath, "minus"); + } + element.cachedMinusImage = minusImage; + if (!minusImage) element.cachedMinusImageMissing = true; } - let unitImage; + let unitImage = element.cachedUnitImage; //print("Get image for unit", imageIndexUnit); - if (imageIndexUnit !== undefined){ - unitImage = getByPath(resources, [], "" + (0 + imageIndexUnit)); - //print("Unit image is", unitImage); - } else if (element.Unit){ - unitImage = getByPath(resources, element.ImagePath, getMultistate(element.Unit, "unknown")); + if (!unitImage && !element.cachedUnitImageMissing){ + if (imageIndexUnit !== undefined){ + unitImage = getByPath(resources, [], "" + (0 + imageIndexUnit)); + //print("Unit image is", unitImage); + } else if (element.Unit){ + unitImage = getByPath(resources, element.ImagePath, getMultistate(element.Unit, "unknown")); + } + unitImage = element.cachedUnitImage; + if (!unitImage) element.cachedUnitImageMissing = true; } let numberWidth = (numberOfDigits * firstImage.width) + (Math.max((numberOfDigits - 1),0) * spacing); From 0d0acfe0754ccd100d7e7627414ad88329c37175 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 30 Oct 2022 22:21:40 +0100 Subject: [PATCH 099/179] imageclock - Change from drag to swipe event for widgets --- apps/imageclock/app.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/apps/imageclock/app.js b/apps/imageclock/app.js index 7cbd9f008..7dd619e28 100644 --- a/apps/imageclock/app.js +++ b/apps/imageclock/app.js @@ -752,25 +752,19 @@ let firstDraw = true; let showWidgetsChanged = false; - let currentDragDistance = 0; let restoreWidgetDraw = function(){ require("widget_utils").show(); Bangle.drawWidgets(); }; - - let handleDrag = function(e){ - //print("handleDrag"); - currentDragDistance += e.dy; - if (Math.abs(currentDragDistance) < 10) return; - dragDown = currentDragDistance > 0; - currentDragDistance = 0; - if (!showWidgets && dragDown){ + + let handleSwipe = function(lr, ud){ + if (!showWidgets && ud == 1){ //print("Enable widgets"); restoreWidgetDraw(); showWidgetsChanged = true; } - if (showWidgets && !dragDown){ + if (showWidgets && ud == -1){ //print("Disable widgets"); clearWidgetsDraw(); firstDraw = true; @@ -779,12 +773,12 @@ let firstDraw = true; if (showWidgetsChanged){ showWidgetsChanged = false; //print("Draw after widget change"); - showWidgets = dragDown; + showWidgets = ud == 1; initialDraw(); } }; - Bangle.on('drag', handleDrag); + Bangle.on('swipe', handleSwipe); if (!events || events.includes("pressure")){ Bangle.on('pressure', handlePressure); @@ -823,7 +817,7 @@ let firstDraw = true; Bangle.setHRMPower(0, "imageclock"); Bangle.setBarometerPower(0, 'imageclock'); - Bangle.removeListener('drag', handleDrag); + Bangle.removeListener('swipe', handleSwipe); Bangle.removeListener('lock', handleLock); Bangle.removeListener('charging', handleCharging); Bangle.removeListener('HRM', handleHrm); From 218cfd9c08318a799a8922e1d1d3838eaefa4b0d Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Sun, 6 Nov 2022 01:01:33 +0100 Subject: [PATCH 100/179] Update app.js --- apps/torch/app.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/torch/app.js b/apps/torch/app.js index 78eda214b..418463144 100644 --- a/apps/torch/app.js +++ b/apps/torch/app.js @@ -13,13 +13,11 @@ Bangle.setLCDTimeout(0); g.reset(); g.setColor(settings.bg); g.fillRect(0,0,g.getWidth(),g.getHeight()); - // Any button turns off setWatch(()=>load(), BTN1); if (global.BTN2) setWatch(()=>load(), BTN2); if (global.BTN3) setWatch(()=>load(), BTN3); - -// Press upper left corner to exit (where red back button would be) +// Pressing upper left corner turns off (where red back button would be) Bangle.setUI({ mode : 'custom', back : load From 97ce6bab9ead99a2f145dbb68b824a5d0b9177f1 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 6 Nov 2022 01:09:07 +0100 Subject: [PATCH 101/179] imageclock - Fix color setting in promises --- apps/imageclock/custom.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/imageclock/custom.html b/apps/imageclock/custom.html index e595b51ca..8bf7a7bd0 100644 --- a/apps/imageclock/custom.html +++ b/apps/imageclock/custom.html @@ -714,13 +714,13 @@ } if (addDebug()) code += 'print("Element condition is ' + condition + '");' + "\n"; - code += "" + colorsetting; code += (condition.length > 0 ? "if (" + condition + "){\n" : ""); if (wrapInTimeouts && (plane != 0 || forceUseOrigPlane)){ code += "p = p.then(()=>delay(0)).then(()=>{\n"; } else { code += "p = p.then(()=>{\n"; } + code += "" + colorsetting; if (addDebug()) code += 'print("Drawing element ' + elementIndex + ' with type ' + c.type + ' on plane ' + planeName + '");' + "\n"; code += "draw" + c.type + "(" + planeName + ", wr, wf.Collapsed[" + elementIndex + "].value);\n"; From a06f8d28a6822d50c6fc157779cd2426df05dec3 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 6 Nov 2022 01:45:53 +0100 Subject: [PATCH 102/179] widbars - Set battery bar color on load --- apps/widbars/ChangeLog | 1 + apps/widbars/metadata.json | 2 +- apps/widbars/widget.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/widbars/ChangeLog b/apps/widbars/ChangeLog index 61e28e6e4..0065c1b27 100644 --- a/apps/widbars/ChangeLog +++ b/apps/widbars/ChangeLog @@ -1,3 +1,4 @@ 0.01: New Widget! 0.02: Battery bar turns yellow on charge Memory status bar does not trigger garbage collect +0.03: Set battery color on load diff --git a/apps/widbars/metadata.json b/apps/widbars/metadata.json index a9981305c..06965e77e 100644 --- a/apps/widbars/metadata.json +++ b/apps/widbars/metadata.json @@ -1,7 +1,7 @@ { "id": "widbars", "name": "Bars Widget", - "version": "0.02", + "version": "0.03", "description": "Display several measurements as vertical bars.", "icon": "icon.png", "screenshots": [{"url":"screenshot.png"}], diff --git a/apps/widbars/widget.js b/apps/widbars/widget.js index cceeb0897..0a4bba76c 100644 --- a/apps/widbars/widget.js +++ b/apps/widbars/widget.js @@ -42,7 +42,7 @@ if (top) g .clearRect(x,y, x+w-1,y+top-1); // erase above bar if (f) g.setColor(col).fillRect(x,y+top, x+w-1,y+h-1); // even for f=0.001 this is still 1 pixel high } - let batColor='#0f0'; + let batColor=Bangle.isCharging()?'#ff0':'#0f0'; function draw() { g.reset(); const x = this.x, y = this.y, From 2216f3fb19dfd68c824d3b306722a6a2e564c3db Mon Sep 17 00:00:00 2001 From: Bruce Blore Date: Sat, 5 Nov 2022 21:05:47 -0700 Subject: [PATCH 103/179] Renamed bgtimer to keytimer --- apps/bgtimer/boot.js | 11 ----------- apps/infoclk/app.js | 2 +- apps/infoclk/settings.js | 2 +- apps/{bgtimer => keytimer}/app.js | 8 ++++---- apps/keytimer/boot.js | 11 +++++++++++ apps/{bgtimer => keytimer}/common.js | 2 +- apps/{bgtimer => keytimer}/icon.js | 0 apps/{bgtimer => keytimer}/icon.png | Bin apps/{bgtimer => keytimer}/img/pause.png | Bin apps/{bgtimer => keytimer}/img/play.png | Bin apps/{bgtimer => keytimer}/img/reset.png | Bin apps/{bgtimer => keytimer}/keypad.js | 2 +- apps/{bgtimer => keytimer}/metadata.json | 18 +++++++++--------- apps/{bgtimer => keytimer}/ring.js | 2 +- apps/{bgtimer => keytimer}/timerview.js | 4 ++-- 15 files changed, 31 insertions(+), 31 deletions(-) delete mode 100644 apps/bgtimer/boot.js rename apps/{bgtimer => keytimer}/app.js (79%) create mode 100644 apps/keytimer/boot.js rename apps/{bgtimer => keytimer}/common.js (98%) rename apps/{bgtimer => keytimer}/icon.js (100%) rename apps/{bgtimer => keytimer}/icon.png (100%) rename apps/{bgtimer => keytimer}/img/pause.png (100%) rename apps/{bgtimer => keytimer}/img/play.png (100%) rename apps/{bgtimer => keytimer}/img/reset.png (100%) rename apps/{bgtimer => keytimer}/keypad.js (98%) rename apps/{bgtimer => keytimer}/metadata.json (64%) rename apps/{bgtimer => keytimer}/ring.js (88%) rename apps/{bgtimer => keytimer}/timerview.js (96%) diff --git a/apps/bgtimer/boot.js b/apps/bgtimer/boot.js deleted file mode 100644 index 67840b3ce..000000000 --- a/apps/bgtimer/boot.js +++ /dev/null @@ -1,11 +0,0 @@ -const BGTIMER_common = require("bgtimer-com.js"); - -//Only start the timeout if the timer is running -if (BGTIMER_common.state.running) { - setTimeout(() => { - //Check now to avoid race condition - if (Bangle.BGTIMER_ACTIVE === undefined) { - load('bgtimer-ring.js'); - } - }, BGTIMER_common.getTimeLeft()); -} \ No newline at end of file diff --git a/apps/infoclk/app.js b/apps/infoclk/app.js index 6bc626018..3d51191df 100644 --- a/apps/infoclk/app.js +++ b/apps/infoclk/app.js @@ -40,7 +40,7 @@ let config = Object.assign({ // false = no shortcut // '#LAUNCHER' = open the launcher // any other string = name of app to open - 'stlap', 'bgtimer', 'pomoplus', 'alarm', + 'stlap', 'keytimer', 'pomoplus', 'alarm', 'rpnsci', 'calendar', 'torch', 'weather' ], diff --git a/apps/infoclk/settings.js b/apps/infoclk/settings.js index d12225f99..0bc3d4b15 100644 --- a/apps/infoclk/settings.js +++ b/apps/infoclk/settings.js @@ -37,7 +37,7 @@ // false = no shortcut // '#LAUNCHER' = open the launcher // any other string = name of app to open - 'stlap', 'bgtimer', 'pomoplus', 'alarm', + 'stlap', 'keytimer', 'pomoplus', 'alarm', 'rpnsci', 'calendar', 'torch', 'weather' ], diff --git a/apps/bgtimer/app.js b/apps/keytimer/app.js similarity index 79% rename from apps/bgtimer/app.js rename to apps/keytimer/app.js index 66f22a7a2..7d235f9a8 100644 --- a/apps/bgtimer/app.js +++ b/apps/keytimer/app.js @@ -1,9 +1,9 @@ -Bangle.BGTIMER_ACTIVE = true; -const common = require("bgtimer-com.js"); +Bangle.keytimer_ACTIVE = true; +const common = require("keytimer-com.js"); const storage = require("Storage"); -const keypad = require("bgtimer-keys.js"); -const timerView = require("bgtimer-tview.js"); +const keypad = require("keytimer-keys.js"); +const timerView = require("keytimer-tview.js"); Bangle.loadWidgets(); Bangle.drawWidgets(); diff --git a/apps/keytimer/boot.js b/apps/keytimer/boot.js new file mode 100644 index 000000000..f202bcbdf --- /dev/null +++ b/apps/keytimer/boot.js @@ -0,0 +1,11 @@ +const keytimer_common = require("keytimer-com.js"); + +//Only start the timeout if the timer is running +if (keytimer_common.state.running) { + setTimeout(() => { + //Check now to avoid race condition + if (Bangle.keytimer_ACTIVE === undefined) { + load('keytimer-ring.js'); + } + }, keytimer_common.getTimeLeft()); +} \ No newline at end of file diff --git a/apps/bgtimer/common.js b/apps/keytimer/common.js similarity index 98% rename from apps/bgtimer/common.js rename to apps/keytimer/common.js index 67a6660d3..8c702de66 100644 --- a/apps/bgtimer/common.js +++ b/apps/keytimer/common.js @@ -1,7 +1,7 @@ const storage = require("Storage"); const heatshrink = require("heatshrink"); -exports.STATE_PATH = "bgtimer.state.json"; +exports.STATE_PATH = "keytimer.state.json"; exports.BUTTON_ICONS = { play: heatshrink.decompress(atob("jEYwMAkAGBnACBnwCBn+AAQPgAQPwAQP8AQP/AQXAAQPwAQP8AQP+AQgICBwQUCEAn4FggyBHAQ+CIgQ")), diff --git a/apps/bgtimer/icon.js b/apps/keytimer/icon.js similarity index 100% rename from apps/bgtimer/icon.js rename to apps/keytimer/icon.js diff --git a/apps/bgtimer/icon.png b/apps/keytimer/icon.png similarity index 100% rename from apps/bgtimer/icon.png rename to apps/keytimer/icon.png diff --git a/apps/bgtimer/img/pause.png b/apps/keytimer/img/pause.png similarity index 100% rename from apps/bgtimer/img/pause.png rename to apps/keytimer/img/pause.png diff --git a/apps/bgtimer/img/play.png b/apps/keytimer/img/play.png similarity index 100% rename from apps/bgtimer/img/play.png rename to apps/keytimer/img/play.png diff --git a/apps/bgtimer/img/reset.png b/apps/keytimer/img/reset.png similarity index 100% rename from apps/bgtimer/img/reset.png rename to apps/keytimer/img/reset.png diff --git a/apps/bgtimer/keypad.js b/apps/keytimer/keypad.js similarity index 98% rename from apps/bgtimer/keypad.js rename to apps/keytimer/keypad.js index d08df1e3f..a5edeb2f2 100644 --- a/apps/bgtimer/keypad.js +++ b/apps/keytimer/keypad.js @@ -58,7 +58,7 @@ let StartButton = { common.state.wasRunning = true; common.state.running = true; feedback(true); - require('bgtimer-tview.js').show(common); + require('keytimer-tview.js').show(common); } }; diff --git a/apps/bgtimer/metadata.json b/apps/keytimer/metadata.json similarity index 64% rename from apps/bgtimer/metadata.json rename to apps/keytimer/metadata.json index 3f63d0ec5..a982594f1 100644 --- a/apps/bgtimer/metadata.json +++ b/apps/keytimer/metadata.json @@ -1,6 +1,6 @@ { - "id": "bgtimer", - "name": "Timer", + "id": "keytimer", + "name": "Keypad Timer", "version": "0.02", "description": "A timer with a keypad that runs in the background", "icon": "icon.png", @@ -12,32 +12,32 @@ "allow_emulator": true, "storage": [ { - "name": "bgtimer.app.js", + "name": "keytimer.app.js", "url": "app.js" }, { - "name": "bgtimer.img", + "name": "keytimer.img", "url": "icon.js", "evaluate": true }, { - "name": "bgtimer.boot.js", + "name": "keytimer.boot.js", "url": "boot.js" }, { - "name": "bgtimer-com.js", + "name": "keytimer-com.js", "url": "common.js" }, { - "name": "bgtimer-ring.js", + "name": "keytimer-ring.js", "url": "ring.js" }, { - "name": "bgtimer-keys.js", + "name": "keytimer-keys.js", "url": "keypad.js" }, { - "name": "bgtimer-tview.js", + "name": "keytimer-tview.js", "url": "timerview.js" } ] diff --git a/apps/bgtimer/ring.js b/apps/keytimer/ring.js similarity index 88% rename from apps/bgtimer/ring.js rename to apps/keytimer/ring.js index 9df5cb4bd..c42c11394 100644 --- a/apps/bgtimer/ring.js +++ b/apps/keytimer/ring.js @@ -1,4 +1,4 @@ -const common = require('bgtimer-com.js'); +const common = require('keytimer-com.js'); Bangle.loadWidgets() Bangle.drawWidgets() diff --git a/apps/bgtimer/timerview.js b/apps/keytimer/timerview.js similarity index 96% rename from apps/bgtimer/timerview.js rename to apps/keytimer/timerview.js index 4c9f7acd3..48c896ba0 100644 --- a/apps/bgtimer/timerview.js +++ b/apps/keytimer/timerview.js @@ -39,7 +39,7 @@ function drawTimer() { else return `${parseInt(minutes)}:${pad(seconds)}`; })(), g.getWidth() / 2, g.getHeight() / 2) - if (timeLeft <= 0) load('bgtimer-ring.js'); + if (timeLeft <= 0) load('keytimer-ring.js'); } let timerInterval; @@ -81,7 +81,7 @@ exports.touch = (button, xy) => { common.state.setTime = setTime; common.state.inputString = inputString; clearTimerInterval(); - require('bgtimer-keys.js').show(common); + require('keytimer-keys.js').show(common); } else { if (common.state.running) { //Record the exact moment that we paused From 90a259ce65344d6260819a284a320f65ebb3a4a4 Mon Sep 17 00:00:00 2001 From: Bruce Blore Date: Sat, 5 Nov 2022 22:25:28 -0700 Subject: [PATCH 104/179] Replaced stolen icons --- apps/gallery/ChangeLog | 2 ++ apps/infoclk/ChangeLog | 3 +++ apps/infoclk/icon.js | 3 +-- apps/infoclk/icon.png | Bin 1989 -> 249 bytes apps/keytimer/ChangeLog | 2 ++ apps/pomoplus/ChangeLog | 3 +++ apps/pomoplus/icon.js | 2 +- apps/pomoplus/icon.png | Bin 2122 -> 1269 bytes apps/pomoplus/metadata.json | 2 +- apps/random/ChangeLog | 2 ++ apps/rpnsci/ChangeLog | 3 +++ apps/stlap/ChangeLog | 3 +++ apps/stlap/icon.js | 2 +- apps/stlap/icon.png | Bin 1566 -> 432 bytes apps/stlapview/ChangeLog | 2 ++ apps/stlapview/icon.js | 2 +- apps/stlapview/icon.png | Bin 1566 -> 564 bytes 17 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 apps/gallery/ChangeLog create mode 100644 apps/infoclk/ChangeLog create mode 100644 apps/keytimer/ChangeLog create mode 100644 apps/pomoplus/ChangeLog create mode 100644 apps/random/ChangeLog create mode 100644 apps/rpnsci/ChangeLog create mode 100644 apps/stlap/ChangeLog create mode 100644 apps/stlapview/ChangeLog diff --git a/apps/gallery/ChangeLog b/apps/gallery/ChangeLog new file mode 100644 index 000000000..76db22053 --- /dev/null +++ b/apps/gallery/ChangeLog @@ -0,0 +1,2 @@ +0.01: New app! +0.02: Submitted to app loader \ No newline at end of file diff --git a/apps/infoclk/ChangeLog b/apps/infoclk/ChangeLog new file mode 100644 index 000000000..4744f872a --- /dev/null +++ b/apps/infoclk/ChangeLog @@ -0,0 +1,3 @@ +0.01: New app! +0.02-0.07: Bug fixes +0.08: Submitted to the app loader \ No newline at end of file diff --git a/apps/infoclk/icon.js b/apps/infoclk/icon.js index 2db8a7a9a..ae230d8f4 100644 --- a/apps/infoclk/icon.js +++ b/apps/infoclk/icon.js @@ -1,2 +1 @@ -//TODO replace app icon with my own -require("heatshrink").decompress(atob("mEwgX/AH4A/AAf+14BBAoPq/Wq1QFB+EP+kLAoNA+CdB3//yEP6ALB/sABYf8gEMgALB6ALJqoLB+tVgH//kQhkQhUABYImCIwPwh3whcA94UCgJHD+AXB/4LCcQQLCKYQLB+EDBZQFCBY/Qh4LJ4ALLl4LFioLCgE/KZMAv4XFBYimBC4/+BYw7DRwQLIV4ILWTQQLDOIUA/ALDAC+t1uv/263/6/Pq/YLC3vv//vM4Oq33rBYP6/u//2/C4Pr1YXC12vBwO+BYO69XmJDQA/ACIA==")) +require("heatshrink").decompress(atob("mEwgOAA4YFS/4AKEf5BlABcAjAgBjAfBAuhH/Apo")) \ No newline at end of file diff --git a/apps/infoclk/icon.png b/apps/infoclk/icon.png index a38093c5f3b6f88dbc9b75017422dbe237d4407f..24423fbd62b2a443ac8a529f2c61a25c781ac1dc 100644 GIT binary patch delta 232 zcmVuE7=Z>Vhein$@==$^0~#fOI^q~5fB>dTug^f-Mq#ZmT))q)rk@=j`;I3$ z9pH;WG0>oGNvH;rBqRyF5ST5A-uxVWfZ}z!!7INFQ6Eqrcp$LnEu?X}VuD^t^u}{E iGD%1hx)IpY0|(#5ZNCagkW>Hw002ovPDHLkV1fYHxnk!4 delta 1986 zcmV;z2R-=t0mToH8Gix*007uvZqNV#2aHKXK~z}7?O0t*Q&$}S(aJ|1h>ls;g4h+@ zB+AGl)8UNHxGbA|xTyGG;sOsoEFnM;B+-{a7Q@E_V_6nMW&&<;@}SXB3>rlzVu;X< zRWXwk`@zScE!aY#?d`|e!>RXPZf_BAEI#a?lbioJ=XcKe-G6(||Kr>ULI_?bk>E9x z{|Wt1=v8G^xDKDsH!(3`G#X=LV-*U8TrOXDqLGmilgUK&#Kc6EN+kdc4-cEoX0}QQ z*}i?dOePafM8w2kFdRO7m=7x{DH$0V5e0j_-m_=V3Z|{9s&YD=eAwyJrv(^`#S%K3 z2qBxzmYSLx`hN`y3JT`t=0fr3&YhD;M7F-UxtYZ<46||L#$^(^di83!ed+D(C4@{& zOjs-yi^VcGH|KCTl9H16n23l7R(HGIbWWX4$8TSNkjR^LcXzY8Ua#-%?PaT@qoV@@ z0~H&dOV(ykrCQkT3X65OnG@Zi=UX7pnuAvM~@a65=02q*VnUpQc}{o zb?ew_S63H*UcpOeWMo7}M)E(H!{MOHjT<+pQd3j2Oe+(oFOl#G1p(}#J#>U2O z-@eU%9{^UX^}>Y<0168WUuvx{Ar!jtTeog?yWPRTtL6=FZEYMVBWjNgS_V&)sPS%G}B_$%Z5oY6qtTenW{1Nu^g`m} z<4>G8QB+jKf{jMwlP6E8URztc{8*NimDSVJLv{8QshCWryu3WB-@kuHJ4%z_z)>FVmDx>~KaTCMyOIXO8QA0HnT74;HACXwg7ckH-_vDjOOaLMP{&$oTm9qN2UoY*s3j zp$k-3SBvIDeSLkQ;GCQstJS(Np~a>jgpg;?o|ToA30{|B7!pRFK7CqOSGQ-+9vU&4 zo0~=15JIkBzg|&MQBhHG^5n^>si{yvL^#7CggBi}n!+lT%5dRAkoEfg{-~&^mwyJV zg`(%{c5_{|Li5heVRRH03*>SnCSvt!A;4yX)rzSpC=^gC5figulK+bG%P%A?jR3)- zRuhee>z$q^RaIOsK(=io_wFrts9#0e+U70BmOFQXfFFJk2WYhdLRKr$>4@J?2q6v! z`Qs1b^%6qJ>@4Z+CDg1@L7z6pDG^{(i2SkbpPdKwMlnD;pTVci*9=hFgSs zgt0MHSEIZfVy=i!h!F4{kf=Wi^-z~Cfu=;}wcszLg7?YD27=M7%NyqKl1-Cm`wryLQYX}5_n<$Y$t;Rd=@Cijlp`igT z7pA8X8;jgrI2<^029c4dtqtxYA+Xy~SqZxxem@;2l_EMiSR_mQl~P#=wHoig549R) zWtf>+0YAjI`L;Gf2&t&xTJ(C-(h}Cne*HDfRr)^@l?oqxz*T?xiGSU)*;zC{H zE;Kda=byp9j!jSF`|t7mIj3K~jM-Uw_S)K@(Lke_XY-4Z^XGBv7Lt>LRjn4!pHo7A z{t3Gs9uLjDk)4gKEL^_K4gLLhIGynM0N~CYeEB6*D%`pSU~mw5dC1L0ZZ0gAr4fpb z#+z^A-FJgkyB$6sHGlhEyD&AyUdQ2bp|us6nb7Oe-Hnew#wVYEy>UvVFc>g11H1h{ ziS|=dXl%rhBS=q&%Y_36AV}0d{S^-&q4nIc68v%6&MW2&W1#Sn>XQf;(x2J0BqTUEnC3*|HA1l zEy&D-(a5<(Lh$z69KdWwOblM!|B#xBHEXEZd%eW%CT=(JdO4k+urdq>AVk>96Q`5N z<>FSIpHBh-Vlss_`<9lKNk2L}#ngwjPIXiTSuzz@0DyR1QVY3BO*tgz-R4N2842(v2JWwjJb}a{Z?UMX|0QIbl USs20!PXGV_07*qoM6N<$f};A%-v9sr diff --git a/apps/keytimer/ChangeLog b/apps/keytimer/ChangeLog new file mode 100644 index 000000000..c819919ed --- /dev/null +++ b/apps/keytimer/ChangeLog @@ -0,0 +1,2 @@ +0.01: New app! +0.02: Submitted to the app loader \ No newline at end of file diff --git a/apps/pomoplus/ChangeLog b/apps/pomoplus/ChangeLog new file mode 100644 index 000000000..1a137aad0 --- /dev/null +++ b/apps/pomoplus/ChangeLog @@ -0,0 +1,3 @@ +0.01: New app! +0.02-0.04: Bug fixes +0.05: Submitted to the app loader \ No newline at end of file diff --git a/apps/pomoplus/icon.js b/apps/pomoplus/icon.js index 020df6f5c..e4ecc7d1c 100644 --- a/apps/pomoplus/icon.js +++ b/apps/pomoplus/icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwwgQNhvQFCoXX7ooQFy0N7vdCYQDDIJ4YDC6QwC7oDBDwYcLN4QRDAApELEYYWGBQKEFCAoWKBIRaIBIIFEEA5iEEooUEDgYhEFxgDB6BfFGAgeFCAYXCBhAEJGYYrGMxQJDC4aIHHIjhGBQQXNE5L5DCIq3GIgiuHWQ7SHhoXKABRCBC6plDC6xVKJBgXVGIIWVAH5pTQK4X/cRAXvJCnQC7JIUCwQwTFwYwTCwgwSC4owQIwowQCw4wPCxAYNFxIYMCxgYJCpoZHBpI=")) +require("heatshrink").decompress(atob("mEwwcBkmSpICG5AIHCLMmoQOKycJAoUyiQRLAgIOBAQQyKsmSpAROpgEBhmQzIHBC4JTIDIxcHDQYgCBQUSphEGpMJkwcEwgLByBoFCIMyCIgpDL4RQEBwWQ5ICBDoRKCBAIFBNYeSjJHDKYYaCR4YLBiYgDKYo4DEwQgECIpiECISqFkJlCCIILETwYRGDo1CsiJECIiPCdIaqCSoabFCgYRHAQ5iBCJ8hcAgRNKwOQgARLU4IRCvwRMa4QRPfwQR5YooR/cAYOGgAADvwEDCI8H/4AG/Ek5IRXGpMkzJZNoQGByYRNiQJCsgRLyAJDpgRQpIRLwgJEWxARBkIJFUg4RChIJGQA4RJNw4RKLg0kCJQ4DVoUACIY")) \ No newline at end of file diff --git a/apps/pomoplus/icon.png b/apps/pomoplus/icon.png index 4ea72f270d5633755b90ede38c67cdc7e121e4c5..60d8023dbc454fead695a3af38600b584664d1df 100644 GIT binary patch delta 1250 zcmV<81ReXz5cLU=BYy_QBu_s_W1vYSoRW6*s#06+-m{}I6ba)1y+I9<2% zK00kx1RlcyjtdNVhUYcns{oKeI0J;Riy{05bZ#tC1IN-p8Kx5hM;eE=clj z3L)>2H(mm77X+~j0lkdY8W4fLBZCkE0*uY9TNB0TL`%@AXcRfYG!7bx(O#58;;YzC(-o43rd3)PzDLspINOgkVmV6e~EkI@er z;kM$pk?Y(VP2lWzDbYE{Tns2|{zZoaS4b?dG$%41c?ICm^I`diz`jwQK^3g`C} z1s_mNaOqJqh3Tab&M6UKquR!oV9o*JYFuKXS0}0P+0grN$cmR$GyP0G*0U(2wXJjl zQGeP9ovxo$Pspn=VpmXXCNp;t08=combsF|{UJ`pUu!_QbETZg0AK{#7X;b%X`95d zlu+t7@=I0=^$9ew_Bn6K?HqZ6o~~am0{e~#U=Fy(s*QU2h!THU;gU?wMWFTU%P7=> zy^2EE3i9T`b)n-{WNQk|>-riBVdtAw;(wNx*4}T?K>Dm=63;#>t$x-EJyV5R;MY)S zY^O1if%@)etI#$S;#siYl6Lxmrx3VrYqp^+KbG%5gF=%nr5@Pkbzt70Ru6-eSbEt? z-1}^{rPS@|7KQ9=3RAB!OUGf$k&$Mu%rBkTtIC?^d!CsBFsB5ybm-}YUQQuJOn-aT zjS5+h7j;apj8;$Pbh63IizSv6#%`iQvWfT8&oZT!4?Ps}XE-e%v?4HfB2ra;em9^? zZ_!S#DP;WK<~XyvYnCoOa%_39cK>fER5L#1YQs986R)7q?XoYv_~_07Kak&rVY|Vb zkaatW!>A&0csj+dyF zZ|V&cX}HY$1aQq<7dyHJwLO?d_+uKpvjcpK%obPvQ^mhG>9Xw)N|?mDA7t(x00000 MNkvXXu0mjf0D^#Bu>b%7 delta 2110 zcmV-E2*LOD3Ca+VBYyx1a7bBm000ie000ie0hKEb8vp z@AG}$=led-d)_1dPm)AItHFLj53o0k(}9&3x6n9{CXy&(cR5(NdI z8z_ZwI#ws1r6q})3WnN*b%L${*MP^so&&7`idH??b${Tn!N&yOGpr=E-M85ZYzCU4 z+^b~Rb)jaUA9yN^)4JBlk`5$MQ>Q_n&;vj(a5Rk5s1@ii z=n$+1K7R#l1?x3b5MbDhr&%#K>s0GZ8n#dH^Dv&C9gUiH2t91@Tj0&EIK5Gq1D=PW z!B4^ZgbI06{(jkDXIGq_NTQ$!+zsqv6mw|`of`9j*X2B)|;~sqEXX$Bgu;ANXHSC7( zKPl9oo3kQtmtpNf?*m7=;&c$KNAQBMLm7DAqZfDu?5jx>wA6F}mjMnLMETIn3DW>* z7jPa}Yj6l>fXrE7R`7QrUvbr8*xNu{ZUN1LO~8JzeMuCwfvy7o0CIG(>~A;dpkdqc zV1LTkyl1Z)JUD-0SPHuA7NYG1O&Ns3-U6+w7%KNX1@;PPH_&Yug42eckaKt&&|(#0 z&ItX%u>D=}^l%ad9l)2tK5u9PaHn5O043maLTAD_t%|^73xJ<-Gp*-=uLHY5CEz~6 zQ3pPo(QJiSV$R6~EO6ijs8_CH?*Wb&Hh-n8f;dV&E_8G>3buN?F9JISLm7D2Ud^Dr zz#ZTzlte+NVb7EyRDzcR2f+@6aoP_w0|$U#0}oaQ(Pj-!0nZAZbf8qoAR06q^oDUd zX4oO2r@&4EX(dCkMc6)IBUo0{dR?5#;~=;n*fJV5Q5=n$3b=~8A)EHxf^7k|8-Mx} zKv$ezPom&u;39A@ZlTQp4fl|t$7sA#9?{vk}Q^2c96ubt6-gXNx z0XiARX(@?7^hdlI8A_G`D+o; zW#C$cLIC=B_G=Oao4_uF@$@C&Qh&auThKfSwpBUsbM#F@Yl^ty)0+=bJ__bS`(5DP zBnn;t-VGPnb!PPg*aG~*U*Tf%LtSxtGKqr229JQX`+t%C3*a|& z>kW%QPiAW`vuAmjIoGRo3WCoR4O{Q_FPb+?HKfPyd&(xV*~vyQ_(~E5r^7fM9*u&- zLVJK!U>Q|f!P*v~M_sx>cR}crlmS#{A!_Qi%3OJz2)AGncHFQZ<2Gso?wPt5r$>Fd zV0D(Ns$_9^OS=c$4SIGo3V&9G@$@yJ9|4~YDx?vqfpgr@eJ__Zw zbTxGfxa@UtGzxy=7ySiqxLxQA%cV_TH!LUs%_~hIFC7MZ1V0#!f_8A3N@y$Y6|+3% za&-VDQSbrS>U;#2io`-$Vlf>^fZqcj0K0)Tiws}47&cO@fVKsi)PGKJR;TVIH2D7f z#8~_FrXC%bEXr*Ks>3qRiHfdy+R}P8e``Hoj?P2@m)^>Q=kK+|a&udc-iWh}=^8G8 z4QB?KcQH?|%tC#7cG*Xu1OF<3&Sf5Xugdq#*SuaSBK7H&YP)U;9PuPpDI!J@Jf8@HUE0{4V*It;mkt*&_b zEbudf^cJSj4DfsgzRCe-lw&}SO8)6BKq3F+4DJ}SEL9E&5`V#SLYHr~EF?4mc9c0M z7}fhWFGqJQ$XwUnM2u$-|a^ch2E1xJD3Ekv8V)LXRrg)SNVMecOEvymL$V39h4 zJN+J63cRz?p!kmuPaF2A&{~7GY@lUQsASlPPz)Rk<8*MT4tZG?MU$urbKi%*2=-~A zUc=T3HP=HS+`-Z!qb+89dNwudx8lW%}kGC+CwY^&Wa)KJI;(Bw|>UFyQa@9y+B0CIlr zbDb@uJx|}&>+v}(q!rD{#b5vcRQMUl24Vp47LI`o0z`{HV1M-47yy_hehfkh5G(#z z{Tg>U6AFMi;Ri=@u&n0E<3-&=MI~RXlB@DFArnc^gdyu=&2V zUw%F+e-E%yG4pqM>Z^plCd>dUWC42E$}VWR4OBcWW!+e(Wudk`WkRR91007*qoM6N<$f&fVJ BwnhK| delta 1550 zcmV+p2J!i@1D*_!BYyw}VoOIv0RI600RN!9r;`8x1=C4HK~!jg?U-9kR7V)ce`kSZ zaWC9NanZDrZGihXw&#$)jrm=iAGIK8xtz&C7L#UsP>_)mll=w zMNO+ffoiD_T1#yUim(D(ys%vMfQPeirVqOZR|L*1ZtO$(KYz{4`ELI?GvCZNFpX*a zzoEp_*#5&O&x5keLhSsu*Gux_<Sozv!G2Zyuqle<|FEQQ*V@1ifU2|*(wSZq44wWAN?1QdY^y4=phZ{UNv^6Lc zc>;mW+6*TlyMG;kBwfcbI6!~;%!3H3vD;3uHb1y^>(-=zV`ddl5V7JHiYPgG;Qe18 zAA!pHJPcz8PzubD)EWei75&!W%;@hc9rI076y7*~pzNrOp{Wz7xR8Pp+Ka+lOmQjN zgh6hHk7s??NidA)sQOMEC`*&EF||E#qBa*omB7O2VSle9DOfTq)lr<`PVzdE$VpBD zpmQjMUkgzc2!<+e_i27DG6#BUZr!wEAw+((0R3rhg#a#W&AA;jk%;M240!=-MS4mK=e~ z`n*WC0iZn3t5^jOVFEXNlM{e2iLwRWs1flt6*bv1p~(>l=lMhkZ`e&anNoVKzIIyM zZc4e>GA}dXX=n04r0c?#ut!GEI*`K+9>Rwd0OfgJm+Z!AZS&F6)+QyZ0Q>U1&if-` zBYzb&mcQAWfJ0kDph|ZjAf;27?qZHTQH^w+B-qwi=~xp` zC^DO`%X0tfMog^E`)xVoZ+l^QM zl2xNP(`}FHE}l>@0+~NB-)zoJu}>yBihsWTe!lqX$Y}q|qZQn_+byL#H~9e{^Cyxs zA@K+Bn9Xdv+|}u9O)Z1>?$KSak~>AK(L*|C&Q(e2&Pjg2$HPbX7{qj$le(M$A|j}a z43ExGVxpWYL)J+IGE1o6Y~Ip`rHrmBDr9z678w_6$gDrh?5r$SuPm0*9pj_VN`GEv zT5bR{0Xj6DrzG}4s>j3EpMT1a)jt8Ss%SYLw_Cy$v}^iU-;=_cfKaZ0SOQSht?Gs8 zE~%aDal2W+_GKB-2XL;tKLmucox&9>d6`XIZ8j@!_e$Lm9|hmt>bvj55SBaNntrAr?+kAM0Bgg9fRV@+Ufeh@fjc6T)U)ff|n6bu2|n>wRr zM>)!d6_&FlTMv{2A%LcVA=jby?hy<5m~pVVZ#dP=fx>J ztJEz5af%2DfIO#NEziwy6=ulQ3bj2d+nYMos5KAJj=>r>6gI{Z&eUG!Dr&N^*}emo zMh|D(6V-LuY4+kww>>9034d?Y!&avjqB;=NPj>a{QK{05;ul7Yl2~T`(Fg#XKAjwX zJrM5zPD}amp(DgcI0xU8eMT9JM}OR{sL2i&;9?{4Lw!_q<+FAX;|Z5R?_~jNUqMz00000Ne4wvM6N<$f{y9$ A761SM diff --git a/apps/stlapview/ChangeLog b/apps/stlapview/ChangeLog new file mode 100644 index 000000000..c819919ed --- /dev/null +++ b/apps/stlapview/ChangeLog @@ -0,0 +1,2 @@ +0.01: New app! +0.02: Submitted to the app loader \ No newline at end of file diff --git a/apps/stlapview/icon.js b/apps/stlapview/icon.js index 32281b7ab..9e10b10a8 100644 --- a/apps/stlapview/icon.js +++ b/apps/stlapview/icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEw4UA///vvvvEF/muH+cDHgPABf4AElWoKhILClALH1WqAQIWHBYIABwAKEgQKD1WgBYkK1X1r4XHlWtqtVvQLG1XVBYNXHYsC1YJBBoPqC4kKEQILCvQ7EhW1BYdeBYkqytVqwCCQwkqCgILCq4LFIoILCqoLEIwIsBGQJIBBZ+pA4Na0oDBtQLGvSFCBaYjIHYR3CI5AADBYhrCAAaDHAASDGQASGCBYizCAASzFZYQACZYrjCIwb7QHgIkCvQ6EGAWq+tf1QuEGAWqAAQuFEgQKBEQw9DHIwAuA=")) +require("heatshrink").decompress(atob("mEwwcCpMkyQCCB4oLFAQsf/4AC/ARvIYM//hHNAQIRBBxgRliQECCJgHFCJWJA4slCJEiDI+UIhYCFAw1IJ5NSAwtECI8/yVKNBOQYYMCpP/Nw2RAgYQBAAMP/gIBlIRHCAYAB8gRGRgVICIsESQwRCoANBA4OAAgIRGJgQRBSQWeCIck0gRFBYmf4AXDCI5BCkn/5ARGagSMBCIUn/xfBSQLaDCIiwD+SDBCJyVCCJrCCCJtPYQQROYQQ1OboYRKR4bdCCJChFCIShCCI7FDbooRCdJAXFa4wRBgAFBwARLIIIAFfY2JO4YAFNYMlQ4YRDkgSGCIuRAgaSBEAI7ChMpCJCzFgEBCImSCJEgCQPpBIlECI5NCjoJEpARISQMDPoYCBWAYCEL4V0BIjaDAQmeCI6SFAQMlkvACI5uGAYO4CJBKEBAWX//0yQ=")) \ No newline at end of file diff --git a/apps/stlapview/icon.png b/apps/stlapview/icon.png index 92ffe73b7f172f7019486231d5bc0ba327c13a67..be24b8e6f9e0b034a69e5b7fc5d29db54056c1c0 100644 GIT binary patch delta 540 zcmV+%0^|Lj473E0BYy$$1Zj2!xaOf9RYsSEJxApsi=7{o6|RV*xc? zm-uH3hFBx(LyOM`Z`rkZQOrtFv6BpN6U+w7AiHRbTX|_wMvR zfXMtj*LE%;cAg&H+vC$A5Gz`f8-ob|M1_|?J`e{$Z{aZzBY(hX@fQs5h5_JH;%yKl zz*zBD^g8d@2?D?>9)*0LT=VF%+%^PwnngSkUN-BtVDY$|IsjOOzd_QWk0=!NA&sXq z*^h~TP?!smQegUajsRNXH9?*=?J`m#BJtWy5N9$)mhT35ZCY7vd$I!vK;mWuEO+Dj zAcg_h#P9xz_kVd5hXNRreR*VhoP0wF5v%|xYfsrcna>Nilz`%W5r7+nlL6q}c47yx zcxfC@5K?aiO)dmRz|w_KK-r`#Zdqh$fzaa07TrZGihXw&#$)jrm=iAGIK8xtz&C7L#UsP>_)mll=w zMNO+ffoiD_T1#yUim(D(ys%vMfQPeirVqOZR|L*1ZtO$(KYz{4`ELI?GvCZNFpX*a zzoEp_*#5&O&x5keLhSsu*Gux_<Sozv!G2Zyuqle<|FEQQ*V@1ifU2|*(wSZq44wWAN?1QdY^y4=phZ{UNv^6Lc zc>;mW+6*TlyMG;kBwfcbI6!~;%!3H3vD;3uHb1y^>(-=zV`ddl5V7JHiYPgG;Qe18 zAA!pHJPcz8PzubD)EWei75&!W%;@hc9rI076y7*~pzNrOp{Wz7xR8Pp+Ka+lOmQjN zgh6hHk7s??NidA)sQOMEC`*&EF||E#qBa*omB7O2VSle9DOfTq)lr<`PVzdE$VpBD zpmQjMUkgzc2!<+e_i27DG6#BUZr!wEAw+((0R3rhg#a#W&AA;jk%;M240!=-MS4mK=e~ z`n*WC0iZn3t5^jOVFEXNlM{e2iLwRWs1flt6*bv1p~(>l=lMhkZ`e&anNoVKzIIyM zZc4e>GA}dXX=n04r0c?#ut!GEI*`K+9>Rwd0OfgJm+Z!AZS&F6)+QyZ0Q>U1&if-` zBYzb&mcQAWfJ0kDph|ZjAf;27?qZHTQH^w+B-qwi=~xp` zC^DO`%X0tfMog^E`)xVoZ+l^QM zl2xNP(`}FHE}l>@0+~NB-)zoJu}>yBihsWTe!lqX$Y}q|qZQn_+byL#H~9e{^Cyxs zA@K+Bn9Xdv+|}u9O)Z1>?$KSak~>AK(L*|C&Q(e2&Pjg2$HPbX7{qj$le(M$A|j}a z43ExGVxpWYL)J+IGE1o6Y~Ip`rHrmBDr9z678w_6$gDrh?5r$SuPm0*9pj_VN`GEv zT5bR{0Xj6DrzG}4s>j3EpMT1a)jt8Ss%SYLw_Cy$v}^iU-;=_cfKaZ0SOQSht?Gs8 zE~%aDal2W+_GKB-2XL;tKLmucox&9>d6`XIZ8j@!_e$Lm9|hmt>bvj55SBaNntrAr?+kAM0Bgg9fRV@+Ufeh@fjc6T)U)ff|n6bu2|n>wRr zM>)!d6_&FlTMv{2A%LcVA=jby?hy<5m~pVVZ#dP=fx>J ztJEz5af%2DfIO#NEziwy6=ulQ3bj2d+nYMos5KAJj=>r>6gI{Z&eUG!Dr&N^*}emo zMh|D(6V-LuY4+kww>>9034d?Y!&avjqB;=NPj>a{QK{05;ul7Yl2~T`(Fg#XKAjwX zJrM5zPD}amp(DgcI0xU8eMT9JM}OR{sL2i&;9?{4Lw!_q<+FAX;|Z5R?_~jNUqMz00000Ne4wvM6N<$f~_v^ A8vp Date: Sun, 6 Nov 2022 10:20:03 +0100 Subject: [PATCH 105/179] imageclock - Add UI when first draw is complete --- apps/imageclock/app.js | 77 ++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/apps/imageclock/app.js b/apps/imageclock/app.js index 7dd619e28..3d7a830d2 100644 --- a/apps/imageclock/app.js +++ b/apps/imageclock/app.js @@ -617,6 +617,7 @@ let firstDraw = true; firstDraw=false; requestRefresh = false; endPerfLog("initialDraw"); + if (!Bangle.uiRemove) setUi(); }).catch((e)=>{ print("Error during drawing", e); }); @@ -809,47 +810,49 @@ let firstDraw = true; handleLock(Bangle.isLocked(), true); - Bangle.setUI({ - mode : "clock", - remove : function() { - //print("remove calls"); - // Called to unload all of the clock app - Bangle.setHRMPower(0, "imageclock"); - Bangle.setBarometerPower(0, 'imageclock'); + let setUi = function(){ + Bangle.setUI({ + mode : "clock", + remove : function() { + //print("remove calls"); + // Called to unload all of the clock app + Bangle.setHRMPower(0, "imageclock"); + Bangle.setBarometerPower(0, 'imageclock'); - Bangle.removeListener('swipe', handleSwipe); - Bangle.removeListener('lock', handleLock); - Bangle.removeListener('charging', handleCharging); - Bangle.removeListener('HRM', handleHrm); - Bangle.removeListener('pressure', handlePressure); + Bangle.removeListener('swipe', handleSwipe); + Bangle.removeListener('lock', handleLock); + Bangle.removeListener('charging', handleCharging); + Bangle.removeListener('HRM', handleHrm); + Bangle.removeListener('pressure', handlePressure); - if (deferredTimout) clearTimeout(deferredTimout); - if (initialDrawTimeoutUnlocked) clearTimeout(initialDrawTimeoutUnlocked); - if (initialDrawTimeoutLocked) clearTimeout(initialDrawTimeoutLocked); + if (deferredTimout) clearTimeout(deferredTimout); + if (initialDrawTimeoutUnlocked) clearTimeout(initialDrawTimeoutUnlocked); + if (initialDrawTimeoutLocked) clearTimeout(initialDrawTimeoutLocked); - for (let i of unlockedDrawInterval){ - //print("Clearing unlocked", i); - clearInterval(i); + for (let i of global.unlockedDrawInterval){ + //print("Clearing unlocked", i); + clearInterval(i); + } + delete global.unlockedDrawInterval; + for (let i of global.lockedDrawInterval){ + //print("Clearing locked", i); + clearInterval(i); + } + delete global.lockedDrawInterval; + delete global.showWidgets; + delete global.firstDraw; + + delete Bangle.printPerfLog; + if (settings.perflog){ + delete Bangle.resetPerfLog; + delete performanceLog; + } + + cleanupDelays(); + restoreWidgetDraw(); } - delete unlockedDrawInterval; - for (let i of lockedDrawInterval){ - //print("Clearing locked", i); - clearInterval(i); - } - delete lockedDrawInterval; - delete showWidgets; - delete firstDraw; - - delete Bangle.printPerfLog; - if (settings.perflog){ - delete Bangle.resetPerfLog; - delete performanceLog; - } - - cleanupDelays(); - restoreWidgetDraw(); - } - }); + }); + } Bangle.loadWidgets(); clearWidgetsDraw(); From f5d3bb0a529ad4d5742c4338f48e10fee6b4861d Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 6 Nov 2022 01:20:20 +0100 Subject: [PATCH 106/179] imageclock - Bump version --- apps/imageclock/ChangeLog | 4 ++++ apps/imageclock/metadata.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/imageclock/ChangeLog b/apps/imageclock/ChangeLog index f81bbf185..d681176a7 100644 --- a/apps/imageclock/ChangeLog +++ b/apps/imageclock/ChangeLog @@ -12,3 +12,7 @@ 0.10: Fix clock not correctly refreshing when drawing in timeouts option is not on 0.11: Additional option in customizer to force drawing directly Fix some problems in handling timeouts +0.12: Use widget_utils module + Fix colorsetting in promises in generated code + Some performance improvements by caching lookups + Activate UI after first draw is complete to prevent drawing over launcher diff --git a/apps/imageclock/metadata.json b/apps/imageclock/metadata.json index e068b9fa7..51257b435 100644 --- a/apps/imageclock/metadata.json +++ b/apps/imageclock/metadata.json @@ -2,7 +2,7 @@ "id": "imageclock", "name": "Imageclock", "shortName": "Imageclock", - "version": "0.11", + "version": "0.12", "type": "clock", "description": "BETA!!! File formats still subject to change --- This app is a highly customizable watchface. To use it, you need to select a watchface. You can build the watchfaces yourself without programming anything. All you need to do is write some json and create image files.", "icon": "app.png", From 3462b36f9c8e7b0a24871839ab5abadb1d88014b Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Thu, 27 Oct 2022 21:27:02 +0200 Subject: [PATCH 107/179] wid_edit - Wrap loadWidgets instead of replacing it --- apps/wid_edit/boot.js | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/apps/wid_edit/boot.js b/apps/wid_edit/boot.js index 872965c97..8dc120fd6 100644 --- a/apps/wid_edit/boot.js +++ b/apps/wid_edit/boot.js @@ -1,18 +1,14 @@ -Bangle.loadWidgets = function() { - global.WIDGETS={}; - require("Storage").list(/\.wid\.js$/) - .forEach(w=>{ - try { eval(require("Storage").read(w)); } - catch (e) { print(w, e); } - }); - const s = require("Storage").readJSON("wid_edit.json", 1) || {}, - c = s.custom || {}; +Bangle.loadWidgets = (o => ()=>{ + o(); + const s = require("Storage").readJSON("wid_edit.json", 1) || {}; + const c = s.custom || {}; for (const w in c){ if (!(w in WIDGETS)) continue; // widget no longer exists // store defaults of customized values in _WIDGETS - global._WIDGETS=global._WIDGETS||{}; - _WIDGETS[w] = {}; + if (!global._WIDGETS) global._WIDGETS = {}; + if (!global._WIDGETS[w]) global._WIDGETS[w] = {}; Object.keys(c[w]).forEach(k => _WIDGETS[w][k] = WIDGETS[w][k]); + //overide values in widget with configured ones Object.assign(WIDGETS[w], c[w]); } const W = WIDGETS; @@ -21,4 +17,4 @@ Bangle.loadWidgets = function() { .sort() .sort((a, b) => (0|W[b].sortorder)-(0|W[a].sortorder)) .forEach(k => WIDGETS[k] = W[k]); -} \ No newline at end of file +})(Bangle.loadWidgets); From 81632cda7efca73e7fef1be515cc6b0e550fec12 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 6 Nov 2022 12:42:11 +0100 Subject: [PATCH 108/179] iconlaunch - Cleanup and reset timeout as needed --- apps/iconlaunch/app.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/iconlaunch/app.js b/apps/iconlaunch/app.js index 479956019..e7cf34840 100644 --- a/apps/iconlaunch/app.js +++ b/apps/iconlaunch/app.js @@ -133,6 +133,7 @@ g.flip(); const itemsN = Math.ceil(launchCache.apps.length / appsN); let onDrag = function(e) { + updateTimeout(); g.setColor(g.theme.fg); g.setBgColor(g.theme.bg); let dy = e.dy; @@ -182,6 +183,7 @@ drag: onDrag, touch: (_, e) => { if (e.y < R.y - 4) return; + updateTimeout(); let i = YtoIdx(e.y); selectItem(i, e); }, @@ -202,16 +204,23 @@ delete idxToY; delete YtoIdx; delete settings; + if (timeout) clearTimeout(timeout); setTimeout(eval, 0, s.read(".bootcde")); }; if (settings.oneClickExit) mode.btn = returnToClock; + + let timeout; + const updateTimeout = function(){ if (settings.timeOut!="Off"){ let time=parseInt(settings.timeOut); //the "s" will be trimmed by the parseInt - setTimeout(returnToClock,time*1000); + if (timeout) clearTimeout(timeout); + timeout = setTimeout(returnToClock,time*1000); + } } + updateTimeout(); Bangle.setUI(mode); } From d3286bab65bb59fb8cdecf63217a6fd238b66029 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 6 Nov 2022 14:20:55 +0100 Subject: [PATCH 109/179] iconlaunch - Bump version --- apps/iconlaunch/ChangeLog | 2 ++ apps/iconlaunch/metadata.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/iconlaunch/ChangeLog b/apps/iconlaunch/ChangeLog index c71da1467..b0fcaf856 100644 --- a/apps/iconlaunch/ChangeLog +++ b/apps/iconlaunch/ChangeLog @@ -12,3 +12,5 @@ used Object.assing for the settings fix cache not deleted when "showClocks" options is changed added timeOut to return to the clock +0.11: Cleanup timeout when changing to clock + Reset timeout on swipe and drag diff --git a/apps/iconlaunch/metadata.json b/apps/iconlaunch/metadata.json index 13e7aee08..8154d830a 100644 --- a/apps/iconlaunch/metadata.json +++ b/apps/iconlaunch/metadata.json @@ -2,7 +2,7 @@ "id": "iconlaunch", "name": "Icon Launcher", "shortName" : "Icon launcher", - "version": "0.10", + "version": "0.11", "icon": "app.png", "description": "A launcher inspired by smartphones, with an icon-only scrollable menu.", "tags": "tool,system,launcher", From ffd85de6356ff33ea069b51f3796c1e977f06960 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Sun, 6 Nov 2022 15:15:42 +0100 Subject: [PATCH 110/179] Fast load to clockface on B2 --- apps/dtlaunch/ChangeLog | 1 + apps/dtlaunch/app-b2.js | 114 +++++++++++++++++++++++++----------- apps/dtlaunch/metadata.json | 2 +- 3 files changed, 83 insertions(+), 34 deletions(-) diff --git a/apps/dtlaunch/ChangeLog b/apps/dtlaunch/ChangeLog index 16c550334..05a1637c0 100644 --- a/apps/dtlaunch/ChangeLog +++ b/apps/dtlaunch/ChangeLog @@ -14,3 +14,4 @@ 0.14: Don't move pages when doing exit swipe - Bangle 2. 0.15: 'Swipe to exit'-code is slightly altered to be more reliable - Bangle 2. 0.16: Use default Bangle formatter for booleans +0.17: Bangle 2: Fast loading on exit to clock face diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js index 8cd5790bb..ddbb74023 100644 --- a/apps/dtlaunch/app-b2.js +++ b/apps/dtlaunch/app-b2.js @@ -1,28 +1,31 @@ +{ // must be inside our own scope here so that when we are unloaded everything disappears + /* Desktop launcher * */ -var settings = Object.assign({ +let settings = Object.assign({ showClocks: true, showLaunchers: true, direct: false, oneClickExit:false, - swipeExit: false + swipeExit: false, + fastload: false, }, require('Storage').readJSON("dtlaunch.json", true) || {}); if( settings.oneClickExit) - setWatch(_=> load(), BTN1); + setWatch(_=> returnToClock, BTN1); -var s = require("Storage"); -var apps = s.list(/\.info$/).map(app=>{ - var a=s.readJSON(app,1); +let s = require("Storage"); + var apps = s.list(/\.info$/).map(app=>{ + let a=s.readJSON(app,1); return a && { name:a.name, type:a.type, icon:a.icon, sortorder:a.sortorder, src:a.src };}).filter( app=>app && (app.type=="app" || (app.type=="clock" && settings.showClocks) || (app.type=="launch" && settings.showLaunchers) || !app.type)); - + apps.sort((a,b)=>{ - var n=(0|a.sortorder)-(0|b.sortorder); + let n=(0|a.sortorder)-(0|b.sortorder); if (n) return n; // do sortorder first if (a.nameb.name) return 1; @@ -33,28 +36,28 @@ apps.forEach(app=>{ app.icon = s.read(app.icon); // should just be a link to a memory area }); -var Napps = apps.length; -var Npages = Math.ceil(Napps/4); -var maxPage = Npages-1; -var selected = -1; -var oldselected = -1; -var page = 0; +let Napps = apps.length; +let Npages = Math.ceil(Napps/4); +let maxPage = Npages-1; +let selected = -1; +let oldselected = -1; +let page = 0; const XOFF = 24; const YOFF = 30; function draw_icon(p,n,selected) { - var x = (n%2)*72+XOFF; - var y = n>1?72+YOFF:YOFF; + let x = (n%2)*72+XOFF; + let y = n>1?72+YOFF:YOFF; (selected?g.setColor(g.theme.fgH):g.setColor(g.theme.bg)).fillRect(x+11,y+3,x+60,y+52); g.clearRect(x+12,y+4,x+59,y+51); g.setColor(g.theme.fg); try{g.drawImage(apps[p*4+n].icon,x+12,y+4);} catch(e){} g.setFontAlign(0,-1,0).setFont("6x8",1); - var txt = apps[p*4+n].name.replace(/([a-z])([A-Z])/g, "$1 $2").split(" "); - var lineY = 0; - var line = ""; + let txt = apps[p*4+n].name.replace(/([a-z])([A-Z])/g, "$1 $2").split(" "); + let lineY = 0; + let line = ""; while (txt.length > 0){ - var c = txt.shift(); + let c = txt.shift(); if (c.length + 1 + line.length > 13){ if (line.length > 0){ @@ -72,24 +75,24 @@ function draw_icon(p,n,selected) { function drawPage(p){ g.reset(); g.clearRect(0,24,175,175); - var O = 88+YOFF/2-12*(Npages/2); - for (var j=0;j{ +function swipeListenerDt(dirLeftRight, dirUpDown){ selected = 0; oldselected=-1; - if(settings.swipeExit && dirLeftRight==1) load(); + if(settings.swipeExit && dirLeftRight==1) returnToClock(); if (dirUpDown==-1||dirLeftRight==-1){ ++page; if (page>maxPage) page=0; drawPage(page); @@ -97,17 +100,18 @@ Bangle.on("swipe",(dirLeftRight, dirUpDown)=>{ --page; if (page<0) page=maxPage; drawPage(page); } -}); +} +Bangle.on("swipe",swipeListenerDt); function isTouched(p,n){ if (n<0 || n>3) return false; - var x1 = (n%2)*72+XOFF; var y1 = n>1?72+YOFF:YOFF; - var x2 = x1+71; var y2 = y1+81; + let x1 = (n%2)*72+XOFF; let y1 = n>1?72+YOFF:YOFF; + let x2 = x1+71; let y2 = y1+81; return (p.x>x1 && p.y>y1 && p.x{ - var i; +function touchListenerDt(_,p){ + let i; for (i=0;i<4;i++){ if((page*4+i){ if (selected!=i && !settings.direct){ draw_icon(page,selected,false); } else { - load(apps[page*4+i].src); + loadApp(apps[page*4+i].src); } } selected=i; @@ -128,9 +132,53 @@ Bangle.on("touch",(_,p)=>{ draw_icon(page,selected,false); selected=-1; } -}); +} +Bangle.on("touch",touchListenerDt); + +const returnToClock = function() { // Delete virtually everything, don't know if some deletes are unnecessary. + Bangle.setUI(); + if (watch) clearWatch(watch); + delete s; + delete a; + delete n; + delete Napps; + delete Npages; + delete maxPage; + delete selected; + delete oldselected; + delete page; + delete XOFF; + delete YOFF; + delete x; + delete y; + delete txt; + delete lineY; + delete line; + delete c; + delete O; + delete x1; + delete x2; + delete i; + Bangle.removeListener("swipe", swipeListenerDt); + Bangle.removeListener("touch", touchListenerDt); + var apps = []; + delete apps; + delete returnToClock; + delete settings; + delete watch; + delete loadApp; + setTimeout(eval, 0, s.read(".bootcde")); + }; + + let watch; + let loadApp; + loadApp = function(name) { + load(name); + }; Bangle.loadWidgets(); g.clear(); Bangle.drawWidgets(); drawPage(0); + +} // end of app scope diff --git a/apps/dtlaunch/metadata.json b/apps/dtlaunch/metadata.json index 36728f342..b71f4ca9b 100644 --- a/apps/dtlaunch/metadata.json +++ b/apps/dtlaunch/metadata.json @@ -1,7 +1,7 @@ { "id": "dtlaunch", "name": "Desktop Launcher", - "version": "0.16", + "version": "0.17", "description": "Desktop style App Launcher with six (four for Bangle 2) apps per page - fast access if you have lots of apps installed.", "screenshots": [{"url":"shot1.png"},{"url":"shot2.png"},{"url":"shot3.png"}], "icon": "icon.png", From 9d71928ba1bc67794a9111e62479b7d1fe0ee96f Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 6 Nov 2022 15:18:05 +0100 Subject: [PATCH 111/179] bthrm - Prevent mixing of internal and external HRM events --- apps/bthrm/lib.js | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/apps/bthrm/lib.js b/apps/bthrm/lib.js index 9e2f0fe63..d9acce90c 100644 --- a/apps/bthrm/lib.js +++ b/apps/bthrm/lib.js @@ -154,8 +154,8 @@ exports.enable = () => { src: "bthrm" }; - log("Emitting HRM", repEvent); - Bangle.emit("HRM_int", repEvent); + log("Emitting aggregated HRM", repEvent); + Bangle.emit("HRM_R", repEvent); } var newEvent = { @@ -538,35 +538,33 @@ exports.enable = () => { }; if (settings.replace){ + // register a listener for original HRM events and emit as HRM_int Bangle.on("HRM", (e) => { e.modified = true; Bangle.emit("HRM_int", e); + if (fallbackActive){ + // if fallback to internal HRM is active, emit as HRM_R to which everyone listens + Bangle.emit("HRM_R", e); + } }); - Bangle.origOn = Bangle.on; - Bangle.on = function(name, callback) { - if (name == "HRM") { - Bangle.origOn("HRM_int", callback); - } else { - Bangle.origOn(name, callback); - } - }; - - Bangle.origRemoveListener = Bangle.removeListener; - Bangle.removeListener = function(name, callback) { - if (name == "HRM") { - Bangle.origRemoveListener("HRM_int", callback); - } else { - Bangle.origRemoveListener(name, callback); - } - }; + // force all apps wanting to listen to HRM to actually get events for HRM_R + Bangle.on = ( o => (name, cb) => { + o = o.bind(Bangle); + if (name == "HRM") o("HRM_R", cb); + else o(name, cb); + })(Bangle.on); + Bangle.removeListener = ( o => (name, cb) => { + o = o.bind(Bangle); + if (name == "HRM") o("HRM_R", cb); + else o(name, cb); + })(Bangle.removeListener); } Bangle.origSetHRMPower = Bangle.setHRMPower; if (settings.startWithHrm){ - Bangle.setHRMPower = function(isOn, app) { log("setHRMPower for " + app + ": " + (isOn?"on":"off")); if (settings.enabled){ From 0f9a117149bfa56104c0b64be870fadb71cd6b6e Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 6 Nov 2022 15:47:54 +0100 Subject: [PATCH 112/179] bthrm - Always use a grace period to force some steps into next idle period --- apps/bthrm/lib.js | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/apps/bthrm/lib.js b/apps/bthrm/lib.js index d9acce90c..3b9e9faa5 100644 --- a/apps/bthrm/lib.js +++ b/apps/bthrm/lib.js @@ -312,13 +312,13 @@ exports.enable = () => { result = result.then(()=>{ log("Starting notifications", newCharacteristic); var startPromise = newCharacteristic.startNotifications().then(()=>log("Notifications started", newCharacteristic)); - if (settings.gracePeriodNotification > 0){ - log("Add " + settings.gracePeriodNotification + "ms grace period after starting notifications"); - startPromise = startPromise.then(()=>{ - log("Wait after connect"); - return waitingPromise(settings.gracePeriodNotification); - }); - } + + log("Add " + settings.gracePeriodNotification + "ms grace period after starting notifications"); + startPromise = startPromise.then(()=>{ + log("Wait after connect"); + return waitingPromise(settings.gracePeriodNotification); + }); + return startPromise; }); } @@ -429,13 +429,11 @@ exports.enable = () => { var connectPromise = gatt.connect(connectSettings).then(function() { log("Connected."); }); - if (settings.gracePeriodConnect > 0){ - log("Add " + settings.gracePeriodConnect + "ms grace period after connecting"); - connectPromise = connectPromise.then(()=>{ - log("Wait after connect"); - return waitingPromise(settings.gracePeriodConnect); - }); - } + log("Add " + settings.gracePeriodConnect + "ms grace period after connecting"); + connectPromise = connectPromise.then(()=>{ + log("Wait after connect"); + return waitingPromise(settings.gracePeriodConnect); + }); return connectPromise; } else { return Promise.resolve(); @@ -476,13 +474,11 @@ exports.enable = () => { log("Supporting service", service.uuid); result = attachServicePromise(result, service); } - if (settings.gracePeriodService > 0) { - log("Add " + settings.gracePeriodService + "ms grace period after services"); - result = result.then(()=>{ - log("Wait after services"); - return waitingPromise(settings.gracePeriodService); - }); - } + log("Add " + settings.gracePeriodService + "ms grace period after services"); + result = result.then(()=>{ + log("Wait after services"); + return waitingPromise(settings.gracePeriodService); + }); return result; }); } else { From 0a1226ad1eeb31056e4f41117435a093c554afe2 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 6 Nov 2022 15:52:14 +0100 Subject: [PATCH 113/179] bthrm - Optionally use bonding for BLE sensor --- apps/bthrm/default.json | 3 ++- apps/bthrm/lib.js | 26 ++++++++++++++------------ apps/bthrm/settings.js | 6 ++++++ 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/apps/bthrm/default.json b/apps/bthrm/default.json index fb284bcd2..2c729ec68 100644 --- a/apps/bthrm/default.json +++ b/apps/bthrm/default.json @@ -16,5 +16,6 @@ "gracePeriodNotification": 0, "gracePeriodConnect": 0, "gracePeriodService": 0, - "gracePeriodRequest": 0 + "gracePeriodRequest": 0, + "bonding": false } diff --git a/apps/bthrm/lib.js b/apps/bthrm/lib.js index 3b9e9faa5..dc3578453 100644 --- a/apps/bthrm/lib.js +++ b/apps/bthrm/lib.js @@ -439,18 +439,20 @@ exports.enable = () => { return Promise.resolve(); } }); - -/* promise = promise.then(() => { - log(JSON.stringify(gatt.getSecurityStatus())); - if (gatt.getSecurityStatus()['bonded']) { - log("Already bonded"); - return Promise.resolve(); - } else { - log("Start bonding"); - return gatt.startBonding() - .then(() => console.log(gatt.getSecurityStatus())); - } - });*/ + + if (settings.bonding){ + promise = promise.then(() => { + log(JSON.stringify(gatt.getSecurityStatus())); + if (gatt.getSecurityStatus()['bonded']) { + log("Already bonded"); + return Promise.resolve(); + } else { + log("Start bonding"); + return gatt.startBonding() + .then(() => console.log(gatt.getSecurityStatus())); + } + }); + } promise = promise.then(()=>{ if (!characteristics || characteristics.length === 0){ diff --git a/apps/bthrm/settings.js b/apps/bthrm/settings.js index 2b19ea46a..fb5aa04da 100644 --- a/apps/bthrm/settings.js +++ b/apps/bthrm/settings.js @@ -96,6 +96,12 @@ writeSettings("debuglog",v); } }, + 'Use bonding': { + value: !!settings.bonding, + onchange: v => { + writeSettings("bonding",v); + } + }, 'Grace periods': function() { E.showMenu(submenu_grace); } }; From e20a47bf35da6bddb35573300c7a5f2916ff4ce6 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Sun, 6 Nov 2022 16:20:42 +0100 Subject: [PATCH 114/179] some tweaks --- apps/dtlaunch/app-b2.js | 62 +++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js index ddbb74023..8bbd9ed5c 100644 --- a/apps/dtlaunch/app-b2.js +++ b/apps/dtlaunch/app-b2.js @@ -10,7 +10,6 @@ let settings = Object.assign({ direct: false, oneClickExit:false, swipeExit: false, - fastload: false, }, require('Storage').readJSON("dtlaunch.json", true) || {}); if( settings.oneClickExit) @@ -45,7 +44,7 @@ let page = 0; const XOFF = 24; const YOFF = 30; -function draw_icon(p,n,selected) { +let drawIcon= function(p,n,selected) { let x = (n%2)*72+XOFF; let y = n>1?72+YOFF:YOFF; (selected?g.setColor(g.theme.fgH):g.setColor(g.theme.bg)).fillRect(x+11,y+3,x+60,y+52); @@ -56,9 +55,8 @@ function draw_icon(p,n,selected) { let txt = apps[p*4+n].name.replace(/([a-z])([A-Z])/g, "$1 $2").split(" "); let lineY = 0; let line = ""; - while (txt.length > 0){ + while (txt.length > 0){ let c = txt.shift(); - if (c.length + 1 + line.length > 13){ if (line.length > 0){ g.drawString(line.trim(),x+36,y+54+lineY*8); @@ -70,9 +68,9 @@ function draw_icon(p,n,selected) { } } g.drawString(line.trim(),x+36,y+54+lineY*8); -} +}; -function drawPage(p){ +let drawPage = function(p){ g.reset(); g.clearRect(0,24,175,175); let O = 88+YOFF/2-12*(Npages/2); @@ -84,12 +82,17 @@ function drawPage(p){ } for (let i=0;i<4;i++) { if (!apps[p*4+i]) return i; - draw_icon(p,i,selected==i && !settings.direct); + drawIcon(p,i,selected==i && !settings.direct); } g.flip(); -} +}; + +Bangle.loadWidgets(); +//g.clear(); +Bangle.drawWidgets(); +drawPage(0); -function swipeListenerDt(dirLeftRight, dirUpDown){ +let swipeListenerDt = function(dirLeftRight, dirUpDown){ selected = 0; oldselected=-1; if(settings.swipeExit && dirLeftRight==1) returnToClock(); @@ -100,27 +103,27 @@ function swipeListenerDt(dirLeftRight, dirUpDown){ --page; if (page<0) page=maxPage; drawPage(page); } -} +}; Bangle.on("swipe",swipeListenerDt); -function isTouched(p,n){ +let isTouched = function(p,n){ if (n<0 || n>3) return false; let x1 = (n%2)*72+XOFF; let y1 = n>1?72+YOFF:YOFF; let x2 = x1+71; let y2 = y1+81; return (p.x>x1 && p.y>y1 && p.x=0 || settings.direct) { if (selected!=i && !settings.direct){ - draw_icon(page,selected,false); + drawIcon(page,selected,false); } else { - loadApp(apps[page*4+i].src); + load(apps[page*4+i].src); } } selected=i; @@ -129,15 +132,14 @@ function touchListenerDt(_,p){ } } if ((i==4 || (page*4+i)>Napps) && selected>=0) { - draw_icon(page,selected,false); + drawIcon(page,selected,false); selected=-1; } -} +}; Bangle.on("touch",touchListenerDt); -const returnToClock = function() { // Delete virtually everything, don't know if some deletes are unnecessary. +const returnToClock = function() { Bangle.setUI(); - if (watch) clearWatch(watch); delete s; delete a; delete n; @@ -159,26 +161,18 @@ const returnToClock = function() { // Delete virtually everything, don't know if delete x1; delete x2; delete i; + delete drawIcon; + delete drawPage; + delete isTouched; Bangle.removeListener("swipe", swipeListenerDt); + delete swipeListenerDt; Bangle.removeListener("touch", touchListenerDt); + delete touchListenerDt; var apps = []; delete apps; delete returnToClock; delete settings; - delete watch; - delete loadApp; setTimeout(eval, 0, s.read(".bootcde")); - }; - - let watch; - let loadApp; - loadApp = function(name) { - load(name); - }; +}; -Bangle.loadWidgets(); -g.clear(); -Bangle.drawWidgets(); -drawPage(0); - } // end of app scope From 5fa96ee5f77dd617b90ffff9904882972d5ce578 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Mon, 24 Oct 2022 12:22:35 +0100 Subject: [PATCH 115/179] New medical info app Initial implementation to enable custom text in the medical alert widget Possible future updates could include better editing UI instead of raw json, more information eg. medications, ability to set info from other apps, etc. Signed-off-by: James Taylor --- apps/medicalinfo/ChangeLog | 1 + apps/medicalinfo/README.md | 27 ++++++ apps/medicalinfo/app-icon.js | 1 + apps/medicalinfo/app.js | 61 ++++++++++++ apps/medicalinfo/app.png | Bin 0 -> 713 bytes apps/medicalinfo/interface.html | 135 ++++++++++++++++++++++++++ apps/medicalinfo/lib.js | 21 ++++ apps/medicalinfo/medicalinfo.json | 6 ++ apps/medicalinfo/metadata.json | 20 ++++ apps/medicalinfo/screenshot_light.png | Bin 0 -> 3053 bytes apps/widmeda/ChangeLog | 1 + apps/widmeda/README.md | 4 +- apps/widmeda/metadata.json | 3 +- apps/widmeda/widget.js | 35 +++++-- 14 files changed, 303 insertions(+), 12 deletions(-) create mode 100644 apps/medicalinfo/ChangeLog create mode 100644 apps/medicalinfo/README.md create mode 100644 apps/medicalinfo/app-icon.js create mode 100644 apps/medicalinfo/app.js create mode 100644 apps/medicalinfo/app.png create mode 100644 apps/medicalinfo/interface.html create mode 100644 apps/medicalinfo/lib.js create mode 100644 apps/medicalinfo/medicalinfo.json create mode 100644 apps/medicalinfo/metadata.json create mode 100644 apps/medicalinfo/screenshot_light.png diff --git a/apps/medicalinfo/ChangeLog b/apps/medicalinfo/ChangeLog new file mode 100644 index 000000000..e8739a121 --- /dev/null +++ b/apps/medicalinfo/ChangeLog @@ -0,0 +1 @@ +0.01: Initial Medical Information application! diff --git a/apps/medicalinfo/README.md b/apps/medicalinfo/README.md new file mode 100644 index 000000000..6dd19d4c6 --- /dev/null +++ b/apps/medicalinfo/README.md @@ -0,0 +1,27 @@ +# Medical Information + +This app displays basic medical information, and provides a common way to set up the `medicalinfo.json` file, which other apps can use if required. + +## Medical information JSON file + +When the app is loaded from the app loader, a file named `medicalinfo.json` is loaded along with the javascript etc. +The file has the following contents: + +``` +{ + "bloodType": "", + "height": "", + "weight": "", + "medicalAlert": [ "" ] +} +``` + +## Medical information editor + +Clicking on the download icon of `Medical Information` in the app loader invokes the editor. +The editor downloads and displays the current `medicalinfo.json` file, which can then be edited. +The edited `medicalinfo.json` file is uploaded to the Bangle by clicking the `Upload` button. + +## Creator + +James Taylor ([jt-nti](https://github.com/jt-nti)) diff --git a/apps/medicalinfo/app-icon.js b/apps/medicalinfo/app-icon.js new file mode 100644 index 000000000..1ae7916fb --- /dev/null +++ b/apps/medicalinfo/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwg+7kUiCykCC4MgFykgDIIXUAQgAMiMRiREBC4YABkILBCxEBC4pHCC4kQFxIXEAAgXCGBERif/+QXHl//mIXJj//+YXHn//+IXL/8yCwsjBIIXNABIX/C63d7oDB+czmaPPC7hHR/oWBAAPfC65HRC7qnXX/4XDABAXkIIQAFI5wXXL/5f/L/5fvC9sTC5cxC5IAOC48BCxsQC44wOCxAArA")) diff --git a/apps/medicalinfo/app.js b/apps/medicalinfo/app.js new file mode 100644 index 000000000..9c4941744 --- /dev/null +++ b/apps/medicalinfo/app.js @@ -0,0 +1,61 @@ +const medicalinfo = require('medicalinfo').load(); +// const medicalinfo = { +// bloodType: "O+", +// height: "166cm", +// weight: "73kg" +// }; + +function hasAlert(info) { + return (Array.isArray(info.medicalAlert)) && (info.medicalAlert[0]); +} + +// No space for widgets! +// TODO: no padlock widget visible so prevent screen locking? + +g.clear(); +const bodyFont = g.getFonts().includes("12x20") ? "12x20" : "6x8:2"; +g.setFont(bodyFont); + +const title = hasAlert(medicalinfo) ? "MEDICAL ALERT" : "Medical Information"; +var lines = []; + +lines = g.wrapString(title, g.getWidth() - 10); +var titleCnt = lines.length; +if (titleCnt) lines.push(""); // add blank line after title + +if (hasAlert(medicalinfo)) { + medicalinfo.medicalAlert.forEach(function (details) { + lines = lines.concat(g.wrapString(details, g.getWidth() - 10)); + }); + lines.push(""); // add blank line after medical alert +} + +if (medicalinfo.bloodType) { + lines = lines.concat(g.wrapString("Blood group: " + medicalinfo.bloodType, g.getWidth() - 10)); +} +if (medicalinfo.height) { + lines = lines.concat(g.wrapString("Height: " + medicalinfo.height, g.getWidth() - 10)); +} +if (medicalinfo.weight) { + lines = lines.concat(g.wrapString("Weight: " + medicalinfo.weight, g.getWidth() - 10)); +} + +lines.push(""); + +// TODO: display instructions for updating medical info if there is none! + +E.showScroller({ + h: g.getFontHeight(), // height of each menu item in pixels + c: lines.length, // number of menu items + // a function to draw a menu item + draw: function (idx, r) { + // FIXME: in 2v13 onwards, clearRect(r) will work fine. There's a bug in 2v12 + g.setBgColor(idx < titleCnt ? g.theme.bg2 : g.theme.bg). + setColor(idx < titleCnt ? g.theme.fg2 : g.theme.fg). + clearRect(r.x, r.y, r.x + r.w, r.y + r.h); + g.setFont(bodyFont).drawString(lines[idx], r.x, r.y); + } +}); + +// Show launcher when button pressed +setWatch(() => load(), process.env.HWVERSION === 2 ? BTN : BTN3, { repeat: false, edge: "falling" }); diff --git a/apps/medicalinfo/app.png b/apps/medicalinfo/app.png new file mode 100644 index 0000000000000000000000000000000000000000..16204ea894c93614f302be7e8c08c04a2c7d884f GIT binary patch literal 713 zcmV;)0yh1LP)JyIpq(iM5zZq3Z;jN z6c2hTQZMl&c=Hfb&q}={R4ix@_QTTt0p5DZWwD-&VEu|#yx8oHhbD21yO~{gHhakY zPCGmA%)C$D_t_iMI3H%}!5LWS&Q5ZUz9FZ503{2(V&Xwc`}b0I&uiVS_x7eV%jyjkY0RH|MTRzMq|* zs8|}kQJ+00`#9Z8P&ljJw z*4UNR)#ft;egI@kr&eygxFGb5&;!}28G}*Hsi)ft*styXs#d>UsS%t5`f`kIfC!kzvR8UQiYALy%wEjX(lg+s19qshwoe(F!OJIMCf5;CtK4XEY3y2ckw= z1-!IO7#`^E3b^&OUz7*_moR$TFWp@MBfTL8NRfWJBE3 + + + + + + +
+ + + + + +

+
+    
+    
+  
+
diff --git a/apps/medicalinfo/lib.js b/apps/medicalinfo/lib.js
new file mode 100644
index 000000000..683005359
--- /dev/null
+++ b/apps/medicalinfo/lib.js
@@ -0,0 +1,21 @@
+const storage = require('Storage');
+
+exports.load = function () {
+  const medicalinfo = storage.readJSON('medicalinfo.json') || {
+    bloodType: "",
+    height: "",
+    weight: "",
+    medicalAlert: [""]
+  };
+
+  // Don't return anything unexpected
+  const expectedMedicalinfo = [
+    "bloodType",
+    "height",
+    "weight",
+    "medicalAlert"
+  ].filter(key => key in medicalinfo)
+    .reduce((obj, key) => (obj[key] = medicalinfo[key], obj), {});
+
+  return expectedMedicalinfo;
+};
diff --git a/apps/medicalinfo/medicalinfo.json b/apps/medicalinfo/medicalinfo.json
new file mode 100644
index 000000000..8b49725cb
--- /dev/null
+++ b/apps/medicalinfo/medicalinfo.json
@@ -0,0 +1,6 @@
+{
+    "bloodType": "",
+    "height": "",
+    "weight": "",
+    "medicalAlert": [ "" ]
+}
diff --git a/apps/medicalinfo/metadata.json b/apps/medicalinfo/metadata.json
new file mode 100644
index 000000000..f1a0c145f
--- /dev/null
+++ b/apps/medicalinfo/metadata.json
@@ -0,0 +1,20 @@
+{ "id": "medicalinfo",
+  "name": "Medical Information",
+  "version":"0.01",
+  "description": "Provides 'medicalinfo.json' used by various health apps, as well as a way to edit it from the App Loader",
+  "icon": "app.png",
+  "tags": "health,medical",
+  "type": "app",
+  "supports" : ["BANGLEJS","BANGLEJS2"],
+  "readme": "README.md",
+  "screenshots": [{"url":"screenshot_light.png"}],
+  "interface": "interface.html",
+  "storage": [
+    {"name":"medicalinfo.app.js","url":"app.js"},
+    {"name":"medicalinfo.img","url":"app-icon.js","evaluate":true},
+    {"name":"medicalinfo","url":"lib.js"}
+  ],
+  "data": [
+    {"name":"medicalinfo.json","url":"medicalinfo.json"}
+  ]
+}
diff --git a/apps/medicalinfo/screenshot_light.png b/apps/medicalinfo/screenshot_light.png
new file mode 100644
index 0000000000000000000000000000000000000000..42970f9fc8589f7947e12e868ad1a43b3aeb6227
GIT binary patch
literal 3053
zcmeH}`#%#77soXtlaxzxm;1e#CaUo@oBRDv#&TPjO0KzOslLV#M&_FDQtqR%i7(d0
zC47~~)9uk(4m&imk8oUD%v%L?=H@g29dfxGc)
z%YQ;hkeA7{&jGx0B*x7e#@9S5&*tMh_RJP;;gJ}yhFnYf+$dW1@eq+v6Z$XYbm~H-UWCr~VCy#GrM8Rf@BF(H!>Y7%{pMFqpaJ_LyMNtd
zKA37?VD5MNVTU230f8-V`u`n~P(
zlsg8YNNx+D0h1j+j9%JnKAw>I0||ICyPq@sfj(4jBRyq0W@1*!f28{uR`N!I{6ujh
zfE2CvrT&e1T#D|t`nE(T^kZ$k6(Ob=29Be3oiz1`Rms-0(Gpl6jTGpC
zE2HDd5$M@)VSI#tY>EdKU1v5^#nZ)h020<`qb_|G7m$jGHFm1&k3XJ*dv&gfJ|;T{
zxhZ-|0SEJD*#++8!HR^ZT;Wu~-?D*U`MU&jx83uaJ@aI%yil>4>$m-17*VH<5~ii)
zG|WOr#o}5xKZH`Cs%%+KT2>rEywYs_#GSl(oywO&^6BZPrjQx-or2?p8R3+4y~M%s
zlPv(=D!o`$zq(gT#?Zl$3K?UD&dd)vxcA5&j_BgI0qbmx7e%x?BG5lt%#Q9em|oOJS!s&f2$GIeFDa|F{lO
zhdOk%493l^vY5%^{1Y^2oPMh64T2ALai;ek;E`}()0~HZD5KPib>aMd;0S$*uaF|u9MM-%gl{mvOZq}&U`8O*k=j(
ziA4&rE6f=B76aaFMTgvt&_zOEL*rVbjGbq0!=`gGS9`_oaaZ(}rH=OTx+pf&XVn23H;39xw4{zmlpu!UwRs}$
zPx~xdd0l#LRC`=Hs2r>>n)TmCPxZVWYvUZG@o&rp7(c94*eh_1olV#b?h$F5={%I^
z*e0npDP1$fPTFn{qUm7rb9)w=m47a`>IF*Iz)J4wz1&5aW{Lrp{Q7qrQOv?Rjj-H?
zIImIagsK@Wz1r23t&R5ESR1&OI`RBX-fq-|FZN~Kf#{$mue6tS@|-A8;|IsA0}-Yd
z&YjtaDImN%*j_@LaXRw~E4&pRz0B-eifC_IYUf6Bp`qD~KFnP^y0z0CrYynGuBfsG
zlP_H|ziheq@d2HL6as$E0$PRIE5HHiVE`;G1JGWA&>NQ@4f
z>WLSlXV$9ZG3r2m42OW1>MRAQauGNs?fa5?GOzIXKU0Xid2OwL)7{tAuMTbvIm$uZ
zYgba$Oo^?ItUeIlI6vvB0oJ_AT!*{Iv4g;Dy@IlJm?P4R#G)566T=}!T;EJ77dxh7
zYbZmY{a;(&b0f~#t-_G!xrz%z!I|Z&d&E+6iReSJJ)58Ar?-Nv6K9B*1lW@WR0{bR
zDp@BJdvRe+88{=DhQ^)zX!7Qd4SLSe;k`8AnFPEX`ux5g~3iomS|FqU+&+tSsp2BxP&ceIi19^l2GC@KZRbO)QQoe
zl1k>@n!`~`xuR}l&A|}`&HkrqNL_5%-TIJ-Y28IF>NV&{#k(jxMxl7R%wD6V)L|mc
z850{xv(EZzSQGDQQ#VyCy&9}Dz&@Z|T*ln0Fsy{5fHrF;`!uftm6$D|^jw4xUa|_x
zWDK2_%!7S35{lcB|32=v@9uifK?c-#_i~byMVVlJ%jt7J5vJ~~gJE~<1-uGRDz~@^
z*HOm`V90IZEoA`de)Wl@GoDjQ-k4+@!cbS|!lFmu=(EOY;BUkkIO@yLRR?bWgSW8u
zU$V~UhI~sd8Z_J0G^@g{=rUFY&}A%O8)=j)+NDm&|i_qCl4mT;MFfx8uq72xv@ur<`h}-vrH$rTJK&
zKK;3y8HrGR!ft0;jf!iXZYXfW?cb*-b8ET!V*;MHTRlEd^u(sJD?jXX_v-Rh-%3|#
zpjOIyVL-8ry(w-;>%JvRDqIrW>b+_MC76<)p&%fwrH_ds)Riz9oHa7pYyS}k_So15
zcz)}zni{ifqe9rRl2xk^2`2Ml{!SBpe(+G)U}YRk-f6*E126hv$9}C|3@d_@%F5?#
zIANLz%I`C2+RROie4~Q<{0-@DIm2mgide~u!VO?W_agT!r>_pe
zuDn@uZe?hbAdfUL+6@M^mLg}CvH3Gif}3JLWJv?Bfo6AoHFLrNn(8eQ842lzdu*7C
zfI+`e$XLVLy8q`w=t2=V!X
zPY4eqGT=)gFgkFQaC|^T6$Kc6IIS$f!^l&NiImI{37-ceqQsL1SfkL_t%Ls`{XZ;x
a=P0M>wWyHO$rrr;ozE8G1aF3+?*1ENc&b {
+  function getAlertText() {
+    const medicalinfo = require("medicalinfo").load();
+    const alertText = ((Array.isArray(medicalinfo.medicalAlert)) && (medicalinfo.medicalAlert[0])) ? medicalinfo.medicalAlert[0] : "";
+    return (g.wrapString(alertText, g.getWidth()).length === 1) ? alertText : "MEDICAL ALERT";
+  }
+
   // Top right star of life logo
-  WIDGETS["widmedatr"]={
+  WIDGETS["widmedatr"] = {
     area: "tr",
     width: 24,
-    draw: function() {
+    draw: function () {
       g.reset();
       g.setColor("#f00");
       g.drawImage(atob("FhYBAAAAA/AAD8AAPwAc/OD/P8P8/x/z/n+/+P5/wP58A/nwP5/x/v/n/P+P8/w/z/Bz84APwAA/AAD8AAAAAA=="), this.x + 1, this.y + 1);
     }
   };
 
-  // Bottom medical alert message
-  WIDGETS["widmedabl"]={
+  // Bottom medical alert text
+  WIDGETS["widmedabl"] = {
     area: "bl",
-    width: Bangle.CLOCK?Bangle.appRect.w:0,
-    draw: function() {
+    width: Bangle.CLOCK ? Bangle.appRect.w : 0,
+    draw: function () {
       // Only show the widget on clocks
       if (!Bangle.CLOCK) return;
 
       g.reset();
       g.setBgColor(g.theme.dark ? "#fff" : "#f00");
       g.setColor(g.theme.dark ? "#f00" : "#fff");
-      g.setFont("Vector",18);
-      g.setFontAlign(0,0);
+      g.setFont("Vector", 16);
+      g.setFontAlign(0, 0);
       g.clearRect(this.x, this.y, this.x + this.width - 1, this.y + 23);
-      g.drawString("MEDICAL ALERT", this.width / 2, this.y + ( 23 / 2 ));
+
+      const alertText = getAlertText();
+      g.drawString(alertText, this.width / 2, this.y + (23 / 2));
     }
   };
+
+  Bangle.on("touch", (_, c) => {
+    const bl = WIDGETS.widmedabl;
+    const tr = WIDGETS.widmedatr;
+    if ((bl && c.x >= bl.x && c.x < bl.x + bl.width && c.y >= bl.y && c.y <= bl.y + 24)
+      || (tr && c.x >= tr.x && c.x < tr.x + tr.width && c.y >= tr.y && c.y <= tr.y + 24)) {
+      load("medicalinfo.app.js");
+    }
+  });
 })();

From 0a22df94b2dc9932b4304eba80582fae07e5f10a Mon Sep 17 00:00:00 2001
From: Martin Boonk 
Date: Sun, 6 Nov 2022 16:11:22 +0100
Subject: [PATCH 116/179] bthrm - Use increasing timeouts if device not found

---
 apps/bthrm/lib.js | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/apps/bthrm/lib.js b/apps/bthrm/lib.js
index dc3578453..652d9ec04 100644
--- a/apps/bthrm/lib.js
+++ b/apps/bthrm/lib.js
@@ -280,7 +280,11 @@ exports.enable = () => {
       log("Disconnect: " + reason);
       log("GATT", gatt);
       log("Characteristics", characteristics);
-      clearRetryTimeout(reason != "Connection Timeout");
+      
+      var retryTimeResetNeeded = true;
+      retryTimeResetNeeded &= reason != "Connection Timeout";
+      retryTimeResetNeeded &= reason != "No device found matching filters";
+      clearRetryTimeout(retryTimeResetNeeded);
       supportedCharacteristics["0x2a37"].active = false;
       startFallback();
       blockInit = false;

From fdcbbefd6c0f92f0f3e46240d5ced09f8af86fb2 Mon Sep 17 00:00:00 2001
From: Martin Boonk 
Date: Sun, 6 Nov 2022 18:53:23 +0100
Subject: [PATCH 117/179] bthrm - Unset timout variable

---
 apps/bthrm/lib.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/apps/bthrm/lib.js b/apps/bthrm/lib.js
index 652d9ec04..13e8b0383 100644
--- a/apps/bthrm/lib.js
+++ b/apps/bthrm/lib.js
@@ -109,6 +109,7 @@ exports.enable = () => {
           if (supportedCharacteristics["0x2a37"].active) stopFallback();
           if (bpmTimeout) clearTimeout(bpmTimeout);
           bpmTimeout = setTimeout(()=>{
+            bpmTimeout = undefined;
             supportedCharacteristics["0x2a37"].active = false;
             startFallback();
           }, 3000);

From 02b5f3be5809bdf29c74396522faf88597baf25b Mon Sep 17 00:00:00 2001
From: thyttan <6uuxstm66@mozmail.com⁩>
Date: Sun, 6 Nov 2022 18:59:16 +0100
Subject: [PATCH 118/179] remove watcher for BTN1

---
 apps/dtlaunch/app-b2.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js
index 8bbd9ed5c..e6620a50b 100644
--- a/apps/dtlaunch/app-b2.js
+++ b/apps/dtlaunch/app-b2.js
@@ -13,7 +13,7 @@ let settings = Object.assign({
 }, require('Storage').readJSON("dtlaunch.json", true) || {});
 
 if( settings.oneClickExit)
-  setWatch(_=> returnToClock, BTN1);
+  let buttonWatch = setWatch(_=> returnToClock, BTN1);
   
 let s = require("Storage");
   var apps = s.list(/\.info$/).map(app=>{
@@ -140,6 +140,7 @@ Bangle.on("touch",touchListenerDt);
   
 const returnToClock = function() {
   Bangle.setUI();
+  clearWatch(buttonWatch);
   delete s;
   delete a;
   delete n;

From eca777c8ecc819a506905b64127142d52074bac9 Mon Sep 17 00:00:00 2001
From: thyttan <6uuxstm66@mozmail.com⁩>
Date: Sun, 6 Nov 2022 19:03:51 +0100
Subject: [PATCH 119/179] fix

---
 apps/dtlaunch/app-b2.js | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js
index e6620a50b..1d36156bc 100644
--- a/apps/dtlaunch/app-b2.js
+++ b/apps/dtlaunch/app-b2.js
@@ -12,8 +12,7 @@ let settings = Object.assign({
   swipeExit: false,
 }, require('Storage').readJSON("dtlaunch.json", true) || {});
 
-if( settings.oneClickExit)
-  let buttonWatch = setWatch(_=> returnToClock, BTN1);
+if (settings.oneClickExit) let buttonWatch = setWatch(_=> returnToClock, BTN1);
   
 let s = require("Storage");
   var apps = s.list(/\.info$/).map(app=>{

From 5e2819bedcb7aed55cc3d143320dd21da70cf53d Mon Sep 17 00:00:00 2001
From: thyttan <6uuxstm66@mozmail.com⁩>
Date: Sun, 6 Nov 2022 19:07:01 +0100
Subject: [PATCH 120/179] new try at fix

---
 apps/dtlaunch/app-b2.js | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js
index 1d36156bc..6b7d0b61b 100644
--- a/apps/dtlaunch/app-b2.js
+++ b/apps/dtlaunch/app-b2.js
@@ -12,8 +12,10 @@ let settings = Object.assign({
   swipeExit: false,
 }, require('Storage').readJSON("dtlaunch.json", true) || {});
 
-if (settings.oneClickExit) let buttonWatch = setWatch(_=> returnToClock, BTN1);
-  
+if (settings.oneClickExit) {
+  let buttonWatch = setWatch(_=> returnToClock, BTN1);
+} 
+
 let s = require("Storage");
   var apps = s.list(/\.info$/).map(app=>{
   let a=s.readJSON(app,1);

From 425675417819a0960668547c1df0572313e46d40 Mon Sep 17 00:00:00 2001
From: Martin Boonk 
Date: Sun, 6 Nov 2022 15:55:35 +0100
Subject: [PATCH 121/179] bthrm - Bump version

---
 apps/bthrm/ChangeLog     | 4 ++++
 apps/bthrm/metadata.json | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/apps/bthrm/ChangeLog b/apps/bthrm/ChangeLog
index a70ae3f8a..c7b5a865f 100644
--- a/apps/bthrm/ChangeLog
+++ b/apps/bthrm/ChangeLog
@@ -30,3 +30,7 @@
       Allow recording unmodified internal HR
       Better connection retry handling
 0.13: Less time used during boot if disabled
+0.14: Allow bonding (Debug menu)
+      Prevent mixing of BT and internal HRM events if both are enabled
+      Always use a grace period (default 0 ms) to decouple some connection steps
+      Device not found errors now utilize increasing timeouts
diff --git a/apps/bthrm/metadata.json b/apps/bthrm/metadata.json
index 7eedd223c..df0ac1fc1 100644
--- a/apps/bthrm/metadata.json
+++ b/apps/bthrm/metadata.json
@@ -2,7 +2,7 @@
   "id": "bthrm",
   "name": "Bluetooth Heart Rate Monitor",
   "shortName": "BT HRM",
-  "version": "0.13",
+  "version": "0.14",
   "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.",
   "icon": "app.png",
   "type": "app",

From 84837228f9c1ce8bf1316191d151fbe5f5179469 Mon Sep 17 00:00:00 2001
From: thyttan <6uuxstm66@mozmail.com⁩>
Date: Sun, 6 Nov 2022 19:21:22 +0100
Subject: [PATCH 122/179] fixfixfix

---
 apps/dtlaunch/app-b2.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js
index 6b7d0b61b..aba09406f 100644
--- a/apps/dtlaunch/app-b2.js
+++ b/apps/dtlaunch/app-b2.js
@@ -13,7 +13,7 @@ let settings = Object.assign({
 }, require('Storage').readJSON("dtlaunch.json", true) || {});
 
 if (settings.oneClickExit) {
-  let buttonWatch = setWatch(_=> returnToClock, BTN1);
+  var buttonWatch = setWatch(_=> returnToClock, BTN1);
 } 
 
 let s = require("Storage");

From 9f17ea5c98c3854fac64429b589e8209035d541d Mon Sep 17 00:00:00 2001
From: Martin Boonk 
Date: Sun, 6 Nov 2022 13:36:14 +0100
Subject: [PATCH 123/179] wid_edit - Access global variables explicitly

---
 apps/wid_edit/boot.js     | 10 +++++-----
 apps/wid_edit/settings.js | 32 ++++++++++++++++----------------
 2 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/apps/wid_edit/boot.js b/apps/wid_edit/boot.js
index 8dc120fd6..3cb545a34 100644
--- a/apps/wid_edit/boot.js
+++ b/apps/wid_edit/boot.js
@@ -7,14 +7,14 @@ Bangle.loadWidgets = (o => ()=>{
     // store defaults of customized values in _WIDGETS
     if (!global._WIDGETS) global._WIDGETS = {};
     if (!global._WIDGETS[w]) global._WIDGETS[w] = {};
-    Object.keys(c[w]).forEach(k => _WIDGETS[w][k] = WIDGETS[w][k]);
+    Object.keys(c[w]).forEach(k => global._WIDGETS[w][k] = global.WIDGETS[w][k]);
     //overide values in widget with configured ones
-    Object.assign(WIDGETS[w], c[w]);
+    Object.assign(global.WIDGETS[w], c[w]);
   }
-  const W = WIDGETS;
-  WIDGETS = {};
+  const W = global.WIDGETS;
+  global.WIDGETS = {};
   Object.keys(W)
     .sort()
     .sort((a, b) => (0|W[b].sortorder)-(0|W[a].sortorder))
-    .forEach(k => WIDGETS[k] = W[k]);
+    .forEach(k => global.WIDGETS[k] = W[k]);
 })(Bangle.loadWidgets);
diff --git a/apps/wid_edit/settings.js b/apps/wid_edit/settings.js
index 0969ed533..5f82cd211 100644
--- a/apps/wid_edit/settings.js
+++ b/apps/wid_edit/settings.js
@@ -9,7 +9,7 @@
 
   let cleanup = false;
   for (const id in settings.custom) {
-    if (!(id in WIDGETS)) {
+    if (!(id in global.WIDGETS)) {
       // widget which no longer exists
       cleanup = true;
       delete settings.custom[id];
@@ -24,12 +24,12 @@
    * Sort & redraw all widgets
    */
   function redrawWidgets() {
-    let W = WIDGETS;
+    let W = global.WIDGETS;
     global.WIDGETS = {};
     Object.keys(W)
       .sort()
       .sort((a, b) => (0|W[b].sortorder)-(0|W[a].sortorder))
-      .forEach(k => {WIDGETS[k] = W[k]});
+      .forEach(k => {global.WIDGETS[k] = W[k];});
     Bangle.drawWidgets();
   }
 
@@ -52,9 +52,9 @@
   }
 
   function edit(id) {
-    let WIDGET = WIDGETS[id],
+    let WIDGET = global.WIDGETS[id],
       def = {area: WIDGET.area, sortorder: WIDGET.sortorder|0}; // default values
-    Object.assign(def, _WIDGETS[id]||{}); // defaults were saved in _WIDGETS
+    Object.assign(def, global._WIDGETS[id]||{}); // defaults were saved in _WIDGETS
 
     settings.custom = settings.custom||{};
     let saved = settings.custom[id] || {},
@@ -102,7 +102,7 @@
         settings.custom = settings.custom || {};
         settings.custom[id] = saved;
       } else if (settings.custom) {
-         delete settings.custom[id]
+         delete settings.custom[id];
       }
       if (!Object.keys(settings.custom).length) delete settings.custom;
       require("Storage").writeJSON("wid_edit.json", settings);
@@ -112,8 +112,8 @@
       let _W = {};
       if (saved.area) _W.area = def.area;
       if ('sortorder' in saved) _W.sortorder = def.sortorder;
-      if (Object.keys(_W).length) _WIDGETS[id] = _W;
-      else delete _WIDGETS[id];
+      if (Object.keys(_W).length) global._WIDGETS[id] = _W;
+      else delete global._WIDGETS[id];
 
       // drawWidgets won't clear e.g. bottom bar if we just disabled the last bottom widget
       redrawWidgets();
@@ -149,7 +149,7 @@
         save();
         mainMenu(); // changing multiple values made the rest of the menu wrong, so take the easy out
       }
-    }
+    };
 
     let m = E.showMenu(menu);
   }
@@ -163,25 +163,25 @@
       if (!Object.keys(_WIDGETS).length) delete _WIDGETS; // no defaults to remember
       back();
     };
-    Object.keys(WIDGETS).forEach(id=>{
+    Object.keys(global.WIDGETS).forEach(id=>{
       // mark customized widgets with asterisk
-      menu[name(id)+((id in _WIDGETS) ? " *" : "")] = () => edit(id);
+      menu[name(id)+((id in global._WIDGETS) ? " *" : "")] = () => edit(id);
     });
-    if (Object.keys(_WIDGETS).length) { // only show reset if there is anything to reset
+    if (Object.keys(global._WIDGETS).length) { // only show reset if there is anything to reset
       menu[/*LANG*/"Reset All"] = () => {
         E.showPrompt(/*LANG*/"Reset all widgets?").then(confirm => {
           if (confirm) {
             delete settings.custom;
             require("Storage").writeJSON("wid_edit.json", settings);
-            for(let id in _WIDGETS) {
-              Object.assign(WIDGETS[id], _WIDGETS[id]) // restore defaults
+            for(let id in global._WIDGETS) {
+              Object.assign(global.WIDGETS[id], global._WIDGETS[id]); // restore defaults
             }
             global._WIDGETS = {};
             redrawWidgets();
           }
           mainMenu(); // reload with reset widgets
-        })
-      }
+        });
+      };
     }
 
     E.showMenu(menu);

From 53661fd11ce6163e9ddf46a209c340d5659b5b91 Mon Sep 17 00:00:00 2001
From: Martin Boonk 
Date: Sun, 6 Nov 2022 13:37:10 +0100
Subject: [PATCH 124/179] wid_edit - Adds back functions as option

---
 apps/wid_edit/settings.js | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/apps/wid_edit/settings.js b/apps/wid_edit/settings.js
index 5f82cd211..6ca9b35c9 100644
--- a/apps/wid_edit/settings.js
+++ b/apps/wid_edit/settings.js
@@ -123,11 +123,11 @@
     }
 
     const menu = {
-      "": {"title": name(id)},
-      /*LANG*/"< Back": () => {
-        redrawWidgets();
-        mainMenu();
-      },
+      "": {"title": name(id),
+        back: () => {
+          redrawWidgets();
+          mainMenu();
+        } },
       /*LANG*/"Side": {
         value: (area === 'tl'),
         format: tl => tl ? /*LANG*/"Left" : /*LANG*/"Right",
@@ -157,11 +157,12 @@
 
   function mainMenu() {
     let menu = {
-      "": {"title": /*LANG*/"Widgets"},
-    };
-    menu[/*LANG*/"< Back"] = ()=>{
-      if (!Object.keys(_WIDGETS).length) delete _WIDGETS; // no defaults to remember
-      back();
+      "": {
+        "title": /*LANG*/"Widgets",
+        back: ()=>{
+          if (!Object.keys(global._WIDGETS).length) delete global._WIDGETS; // no defaults to remember
+          back();
+        }},
     };
     Object.keys(global.WIDGETS).forEach(id=>{
       // mark customized widgets with asterisk

From fa35629f451fbd2246b90f09c99e5dbf2221c44c Mon Sep 17 00:00:00 2001
From: Martin Boonk 
Date: Sun, 6 Nov 2022 19:37:25 +0100
Subject: [PATCH 125/179] wid_edit - Allow setting all areas

---
 apps/wid_edit/settings.js | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/apps/wid_edit/settings.js b/apps/wid_edit/settings.js
index 6ca9b35c9..1d34ae0ca 100644
--- a/apps/wid_edit/settings.js
+++ b/apps/wid_edit/settings.js
@@ -122,17 +122,23 @@
       m.draw();
     }
 
+    const AREA_NAMES = [ "Top left", "Top right", "Bottom left", "Bottom right" ];
+    const AREAS = [ "tl", "tr", "bl", "br" ];
+
     const menu = {
       "": {"title": name(id),
         back: () => {
           redrawWidgets();
           mainMenu();
         } },
-      /*LANG*/"Side": {
-        value: (area === 'tl'),
-        format: tl => tl ? /*LANG*/"Left" : /*LANG*/"Right",
-        onchange: tl => {
-          area = tl ? "tl" : "tr";
+      /*LANG*/"Position": {
+        value: AREAS.indexOf(area),
+        format: v => AREA_NAMES[v],
+        min: 0,
+        max: AREAS.length - 1,
+        onchange: v => {
+          print("v", v);
+          area = AREAS[v];
           save();
         }
       },

From 0c7513335012ae5ac24c29ec6528d24e65bce15b Mon Sep 17 00:00:00 2001
From: Martin Boonk 
Date: Sun, 6 Nov 2022 13:41:33 +0100
Subject: [PATCH 126/179] wid_edit - Bump version

---
 apps/wid_edit/ChangeLog     | 5 ++++-
 apps/wid_edit/metadata.json | 2 +-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/apps/wid_edit/ChangeLog b/apps/wid_edit/ChangeLog
index 2fa857bd8..d8e165029 100644
--- a/apps/wid_edit/ChangeLog
+++ b/apps/wid_edit/ChangeLog
@@ -1 +1,4 @@
-0.01: new Widget Editor!
\ No newline at end of file
+0.01: new Widget Editor!
+0.02: Wrap loadWidgets instead of replacing to keep original functionality intact
+      Change back entry to menu option
+      Allow changing widgets into all areas, including bottom widget bar
diff --git a/apps/wid_edit/metadata.json b/apps/wid_edit/metadata.json
index 66d0192f6..d963a53d0 100644
--- a/apps/wid_edit/metadata.json
+++ b/apps/wid_edit/metadata.json
@@ -1,6 +1,6 @@
 {
   "id": "wid_edit",
-  "version": "0.01",
+  "version": "0.02",
   "name": "Widget Editor",
   "icon": "icon.png",
   "description": "Customize widget locations",

From a46c76a2ffb749d2e8c153e0fce791df01e2ef6c Mon Sep 17 00:00:00 2001
From: thyttan <6uuxstm66@mozmail.com⁩>
Date: Sun, 6 Nov 2022 19:53:28 +0100
Subject: [PATCH 127/179] timeout to clock copied from Icon Launcher

---
 apps/dtlaunch/app-b2.js      | 353 ++++++++++++++++++-----------------
 apps/dtlaunch/settings-b2.js |  29 ++-
 2 files changed, 202 insertions(+), 180 deletions(-)

diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js
index aba09406f..151be96c4 100644
--- a/apps/dtlaunch/app-b2.js
+++ b/apps/dtlaunch/app-b2.js
@@ -1,180 +1,189 @@
 { // must be inside our own scope here so that when we are unloaded everything disappears
-
-/* Desktop launcher
-*
-*/
-
-let settings = Object.assign({
-  showClocks: true,
-  showLaunchers: true,
-  direct: false,
-  oneClickExit:false,
-  swipeExit: false,
-}, require('Storage').readJSON("dtlaunch.json", true) || {});
-
-if (settings.oneClickExit) {
-  var buttonWatch = setWatch(_=> returnToClock, BTN1);
-} 
-
-let s = require("Storage");
-  var apps = s.list(/\.info$/).map(app=>{
-  let a=s.readJSON(app,1);
-  return a && {
-    name:a.name, type:a.type, icon:a.icon, sortorder:a.sortorder, src:a.src
-  };}).filter(
-    app=>app && (app.type=="app" || (app.type=="clock" && settings.showClocks) || (app.type=="launch" && settings.showLaunchers) || !app.type));
   
-apps.sort((a,b)=>{
-  let n=(0|a.sortorder)-(0|b.sortorder);
-  if (n) return n; // do sortorder first
-  if (a.nameb.name) return 1;
-  return 0;
-});
-apps.forEach(app=>{
-    if (app.icon)
-      app.icon = s.read(app.icon); // should just be a link to a memory area
+  /* Desktop launcher
+  *
+  */
+  
+  let settings = Object.assign({
+    showClocks: true,
+    showLaunchers: true,
+    direct: false,
+    oneClickExit: false,
+    swipeExit: false,
+    timeOut: "Off"
+  }, require('Storage').readJSON("dtlaunch.json", true) || {});
+  
+  if (settings.oneClickExit) {
+    var buttonWatch = setWatch(_=> returnToClock, BTN1);
+  } 
+  
+  // taken from Icon Launcher with minor alterations
+  if (settings.timeOut!="Off"){
+    let time=parseInt(settings.timeOut);  //the "s" will be trimmed by the parseInt
+    var timeoutToClock = setTimeout(returnToClock,time*1000);  
+  }
+  let s = require("Storage");
+    var apps = s.list(/\.info$/).map(app=>{
+    let a=s.readJSON(app,1);
+    return a && {
+      name:a.name, type:a.type, icon:a.icon, sortorder:a.sortorder, src:a.src
+    };}).filter(
+      app=>app && (app.type=="app" || (app.type=="clock" && settings.showClocks) || (app.type=="launch" && settings.showLaunchers) || !app.type));
+    
+  apps.sort((a,b)=>{
+    let n=(0|a.sortorder)-(0|b.sortorder);
+    if (n) return n; // do sortorder first
+    if (a.nameb.name) return 1;
+    return 0;
   });
-
-let Napps = apps.length;
-let Npages = Math.ceil(Napps/4);
-let maxPage = Npages-1;
-let selected = -1;
-let oldselected = -1;
-let page = 0;
-const XOFF = 24;
-const YOFF = 30;
-
-let drawIcon= function(p,n,selected) {
-    let x = (n%2)*72+XOFF; 
-    let y = n>1?72+YOFF:YOFF;
-    (selected?g.setColor(g.theme.fgH):g.setColor(g.theme.bg)).fillRect(x+11,y+3,x+60,y+52);
-    g.clearRect(x+12,y+4,x+59,y+51);
-    g.setColor(g.theme.fg);
-    try{g.drawImage(apps[p*4+n].icon,x+12,y+4);} catch(e){}
-    g.setFontAlign(0,-1,0).setFont("6x8",1);
-    let txt =  apps[p*4+n].name.replace(/([a-z])([A-Z])/g, "$1 $2").split(" ");
-    let lineY = 0;
-    let line = "";
-    while (txt.length > 0){
-      let c = txt.shift();
-      if (c.length + 1 + line.length > 13){
-        if (line.length > 0){
-          g.drawString(line.trim(),x+36,y+54+lineY*8);
-          lineY++;
+  apps.forEach(app=>{
+      if (app.icon)
+        app.icon = s.read(app.icon); // should just be a link to a memory area
+    });
+  
+  let Napps = apps.length;
+  let Npages = Math.ceil(Napps/4);
+  let maxPage = Npages-1;
+  let selected = -1;
+  let oldselected = -1;
+  let page = 0;
+  const XOFF = 24;
+  const YOFF = 30;
+  
+  let drawIcon= function(p,n,selected) {
+      let x = (n%2)*72+XOFF; 
+      let y = n>1?72+YOFF:YOFF;
+      (selected?g.setColor(g.theme.fgH):g.setColor(g.theme.bg)).fillRect(x+11,y+3,x+60,y+52);
+      g.clearRect(x+12,y+4,x+59,y+51);
+      g.setColor(g.theme.fg);
+      try{g.drawImage(apps[p*4+n].icon,x+12,y+4);} catch(e){}
+      g.setFontAlign(0,-1,0).setFont("6x8",1);
+      let txt =  apps[p*4+n].name.replace(/([a-z])([A-Z])/g, "$1 $2").split(" ");
+      let lineY = 0;
+      let line = "";
+      while (txt.length > 0){
+        let c = txt.shift();
+        if (c.length + 1 + line.length > 13){
+          if (line.length > 0){
+            g.drawString(line.trim(),x+36,y+54+lineY*8);
+            lineY++;
+          }
+          line = c;
+        } else {
+          line += " " + c;
         }
-        line = c;
-      } else {
-        line += " " + c;
       }
-    }
-    g.drawString(line.trim(),x+36,y+54+lineY*8);
-};
-
-let drawPage = function(p){
-    g.reset();
-    g.clearRect(0,24,175,175);
-    let O = 88+YOFF/2-12*(Npages/2);
-    for (let j=0;jmaxPage) page=0;
-        drawPage(page);
-    } else if (dirUpDown==1||(dirLeftRight==1 && !settings.swipeExit)){
-        --page; if (page<0) page=maxPage;
-        drawPage(page);
-    }
-};
-Bangle.on("swipe",swipeListenerDt);
-
-let isTouched = function(p,n){
-    if (n<0 || n>3) return false;
-    let x1 = (n%2)*72+XOFF;  let y1 =  n>1?72+YOFF:YOFF;
-    let x2 = x1+71; let y2 = y1+81;
-    return (p.x>x1 && p.y>y1 && p.x=0 || settings.direct) {
-                    if (selected!=i && !settings.direct){
-                        drawIcon(page,selected,false);
-                    } else {
-                        load(apps[page*4+i].src);
-                    }
-                }
-                selected=i;
-                break;
-            }
-        }
-    }
-    if ((i==4 || (page*4+i)>Napps) && selected>=0) {
-        drawIcon(page,selected,false);
-        selected=-1;
-    }
-};
-Bangle.on("touch",touchListenerDt);
+  let drawPage = function(p){
+      g.reset();
+      g.clearRect(0,24,175,175);
+      let O = 88+YOFF/2-12*(Npages/2);
+      for (let j=0;jmaxPage) page=0;
+          drawPage(page);
+      } else if (dirUpDown==1||(dirLeftRight==1 && !settings.swipeExit)){
+          --page; if (page<0) page=maxPage;
+          drawPage(page);
+      }
+  };
+  Bangle.on("swipe",swipeListenerDt);
+  
+  let isTouched = function(p,n){
+      if (n<0 || n>3) return false;
+      let x1 = (n%2)*72+XOFF;  let y1 =  n>1?72+YOFF:YOFF;
+      let x2 = x1+71; let y2 = y1+81;
+      return (p.x>x1 && p.y>y1 && p.x=0 || settings.direct) {
+                      if (selected!=i && !settings.direct){
+                          drawIcon(page,selected,false);
+                      } else {
+                          load(apps[page*4+i].src);
+                      }
+                  }
+                  selected=i;
+                  break;
+              }
+          }
+      }
+      if ((i==4 || (page*4+i)>Napps) && selected>=0) {
+          drawIcon(page,selected,false);
+          selected=-1;
+      }
+  };
+  Bangle.on("touch",touchListenerDt);
+    
+  const returnToClock = function() {
+    Bangle.setUI();
+    clearWatch(buttonWatch);
+    delete buttonWatch;
+    clearTimeout(timeoutToClock);
+    delete timeoutToClock;
+    delete s;
+    delete a;
+    delete n;
+    delete Napps;
+    delete Npages;
+    delete maxPage;
+    delete selected;
+    delete oldselected;
+    delete page;
+    delete XOFF;
+    delete YOFF;
+    delete x;
+    delete y;
+    delete txt;
+    delete lineY;
+    delete line;
+    delete c;
+    delete O;
+    delete x1;
+    delete x2;
+    delete i;
+    delete drawIcon;
+    delete drawPage;
+    delete isTouched;
+    Bangle.removeListener("swipe", swipeListenerDt);
+    delete swipeListenerDt;
+    Bangle.removeListener("touch", touchListenerDt);
+    delete touchListenerDt;
+    var apps = [];
+    delete apps;
+    delete returnToClock;
+    delete settings;
+    setTimeout(eval, 0, s.read(".bootcde"));
+  };
   
-const returnToClock = function() {
-  Bangle.setUI();
-  clearWatch(buttonWatch);
-  delete s;
-  delete a;
-  delete n;
-  delete Napps;
-  delete Npages;
-  delete maxPage;
-  delete selected;
-  delete oldselected;
-  delete page;
-  delete XOFF;
-  delete YOFF;
-  delete x;
-  delete y;
-  delete txt;
-  delete lineY;
-  delete line;
-  delete c;
-  delete O;
-  delete x1;
-  delete x2;
-  delete i;
-  delete drawIcon;
-  delete drawPage;
-  delete isTouched;
-  Bangle.removeListener("swipe", swipeListenerDt);
-  delete swipeListenerDt;
-  Bangle.removeListener("touch", touchListenerDt);
-  delete touchListenerDt;
-  var apps = [];
-  delete apps;
-  delete returnToClock;
-  delete settings;
-  setTimeout(eval, 0, s.read(".bootcde"));
-};
-
 } // end of app scope
diff --git a/apps/dtlaunch/settings-b2.js b/apps/dtlaunch/settings-b2.js
index fac9c0fff..315974c77 100644
--- a/apps/dtlaunch/settings-b2.js
+++ b/apps/dtlaunch/settings-b2.js
@@ -6,50 +6,63 @@
     showLaunchers: true,
     direct: false,
     oneClickExit:false,
-    swipeExit: false
+    swipeExit: false,
+    timeOut: "Off"
   }, require('Storage').readJSON(FILE, true) || {});
 
   function writeSettings() {
     require('Storage').writeJSON(FILE, settings);
   }
 
+  const timeOutChoices = [/*LANG*/"Off", "10s", "15s", "20s", "30s"];
+
   E.showMenu({
     "" : { "title" : "Desktop launcher" },
-    "< Back" : () => back(),
-    'Show clocks': {
+    /*LANG*/"< Back" : () => back(),
+    /*LANG*/'Show clocks': {
       value: settings.showClocks,
       onchange: v => {
         settings.showClocks = v;
         writeSettings();
       }
     },
-    'Show launchers': {
+    /*LANG*/'Show launchers': {
       value: settings.showLaunchers,
       onchange: v => {
         settings.showLaunchers = v;
         writeSettings();
       }
     },
-    'Direct launch': {
+    /*LANG*/'Direct launch': {
       value: settings.direct,
       onchange: v => {
         settings.direct = v;
         writeSettings();
       }
     },
-    'Swipe Exit': {
+    /*LANG*/'Swipe Exit': {
       value: settings.swipeExit,
       onchange: v => {
         settings.swipeExit = v;
         writeSettings();
       }
     },
-    'One click exit': {
+    /*LANG*/'One click exit': {
       value: settings.oneClickExit,
       onchange: v => {
         settings.oneClickExit = v;
         writeSettings();
       }
-    }
+    },
+    /*LANG*/'Time Out': {
+      value: timeOutChoices.indexOf(settings.timeOut),
+      min: 0,
+      max: timeOutChoices.length-1,
+      format: v => timeOutChoices[v],
+      onchange: m => {
+        settings.timeOut = m;
+        writeSettings();
+      }
+    },
   });
 })

From 8c427938fdddcdf4a7cd98174b651317705a6b1a Mon Sep 17 00:00:00 2001
From: thyttan <6uuxstm66@mozmail.com⁩>
Date: Sun, 6 Nov 2022 19:54:50 +0100
Subject: [PATCH 128/179] make the diff readable...

---
 apps/dtlaunch/app-b2.js | 362 ++++++++++++++++++++--------------------
 1 file changed, 181 insertions(+), 181 deletions(-)

diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js
index 151be96c4..7c75f291b 100644
--- a/apps/dtlaunch/app-b2.js
+++ b/apps/dtlaunch/app-b2.js
@@ -1,189 +1,189 @@
 { // must be inside our own scope here so that when we are unloaded everything disappears
+
+/* Desktop launcher
+*
+*/
+
+let settings = Object.assign({
+  showClocks: true,
+  showLaunchers: true,
+  direct: false,
+  oneClickExit: false,
+  swipeExit: false,
+  timeOut: "Off"
+}, require('Storage').readJSON("dtlaunch.json", true) || {});
+
+if (settings.oneClickExit) {
+  var buttonWatch = setWatch(_=> returnToClock, BTN1);
+} 
+
+// taken from Icon Launcher with minor alterations
+if (settings.timeOut!="Off"){
+  let time=parseInt(settings.timeOut);  //the "s" will be trimmed by the parseInt
+  var timeoutToClock = setTimeout(returnToClock,time*1000);  
+}
+let s = require("Storage");
+  var apps = s.list(/\.info$/).map(app=>{
+  let a=s.readJSON(app,1);
+  return a && {
+    name:a.name, type:a.type, icon:a.icon, sortorder:a.sortorder, src:a.src
+  };}).filter(
+    app=>app && (app.type=="app" || (app.type=="clock" && settings.showClocks) || (app.type=="launch" && settings.showLaunchers) || !app.type));
   
-  /* Desktop launcher
-  *
-  */
-  
-  let settings = Object.assign({
-    showClocks: true,
-    showLaunchers: true,
-    direct: false,
-    oneClickExit: false,
-    swipeExit: false,
-    timeOut: "Off"
-  }, require('Storage').readJSON("dtlaunch.json", true) || {});
-  
-  if (settings.oneClickExit) {
-    var buttonWatch = setWatch(_=> returnToClock, BTN1);
-  } 
-  
-  // taken from Icon Launcher with minor alterations
-  if (settings.timeOut!="Off"){
-    let time=parseInt(settings.timeOut);  //the "s" will be trimmed by the parseInt
-    var timeoutToClock = setTimeout(returnToClock,time*1000);  
-  }
-  let s = require("Storage");
-    var apps = s.list(/\.info$/).map(app=>{
-    let a=s.readJSON(app,1);
-    return a && {
-      name:a.name, type:a.type, icon:a.icon, sortorder:a.sortorder, src:a.src
-    };}).filter(
-      app=>app && (app.type=="app" || (app.type=="clock" && settings.showClocks) || (app.type=="launch" && settings.showLaunchers) || !app.type));
-    
-  apps.sort((a,b)=>{
-    let n=(0|a.sortorder)-(0|b.sortorder);
-    if (n) return n; // do sortorder first
-    if (a.nameb.name) return 1;
-    return 0;
+apps.sort((a,b)=>{
+  let n=(0|a.sortorder)-(0|b.sortorder);
+  if (n) return n; // do sortorder first
+  if (a.nameb.name) return 1;
+  return 0;
+});
+apps.forEach(app=>{
+    if (app.icon)
+      app.icon = s.read(app.icon); // should just be a link to a memory area
   });
-  apps.forEach(app=>{
-      if (app.icon)
-        app.icon = s.read(app.icon); // should just be a link to a memory area
-    });
-  
-  let Napps = apps.length;
-  let Npages = Math.ceil(Napps/4);
-  let maxPage = Npages-1;
-  let selected = -1;
-  let oldselected = -1;
-  let page = 0;
-  const XOFF = 24;
-  const YOFF = 30;
-  
-  let drawIcon= function(p,n,selected) {
-      let x = (n%2)*72+XOFF; 
-      let y = n>1?72+YOFF:YOFF;
-      (selected?g.setColor(g.theme.fgH):g.setColor(g.theme.bg)).fillRect(x+11,y+3,x+60,y+52);
-      g.clearRect(x+12,y+4,x+59,y+51);
-      g.setColor(g.theme.fg);
-      try{g.drawImage(apps[p*4+n].icon,x+12,y+4);} catch(e){}
-      g.setFontAlign(0,-1,0).setFont("6x8",1);
-      let txt =  apps[p*4+n].name.replace(/([a-z])([A-Z])/g, "$1 $2").split(" ");
-      let lineY = 0;
-      let line = "";
-      while (txt.length > 0){
-        let c = txt.shift();
-        if (c.length + 1 + line.length > 13){
-          if (line.length > 0){
-            g.drawString(line.trim(),x+36,y+54+lineY*8);
-            lineY++;
-          }
-          line = c;
-        } else {
-          line += " " + c;
+
+let Napps = apps.length;
+let Npages = Math.ceil(Napps/4);
+let maxPage = Npages-1;
+let selected = -1;
+let oldselected = -1;
+let page = 0;
+const XOFF = 24;
+const YOFF = 30;
+
+let drawIcon= function(p,n,selected) {
+    let x = (n%2)*72+XOFF; 
+    let y = n>1?72+YOFF:YOFF;
+    (selected?g.setColor(g.theme.fgH):g.setColor(g.theme.bg)).fillRect(x+11,y+3,x+60,y+52);
+    g.clearRect(x+12,y+4,x+59,y+51);
+    g.setColor(g.theme.fg);
+    try{g.drawImage(apps[p*4+n].icon,x+12,y+4);} catch(e){}
+    g.setFontAlign(0,-1,0).setFont("6x8",1);
+    let txt =  apps[p*4+n].name.replace(/([a-z])([A-Z])/g, "$1 $2").split(" ");
+    let lineY = 0;
+    let line = "";
+    while (txt.length > 0){
+      let c = txt.shift();
+      if (c.length + 1 + line.length > 13){
+        if (line.length > 0){
+          g.drawString(line.trim(),x+36,y+54+lineY*8);
+          lineY++;
         }
+        line = c;
+      } else {
+        line += " " + c;
       }
-      g.drawString(line.trim(),x+36,y+54+lineY*8);
-  };
+    }
+    g.drawString(line.trim(),x+36,y+54+lineY*8);
+};
+
+let drawPage = function(p){
+    g.reset();
+    g.clearRect(0,24,175,175);
+    let O = 88+YOFF/2-12*(Npages/2);
+    for (let j=0;jmaxPage) page=0;
-          drawPage(page);
-      } else if (dirUpDown==1||(dirLeftRight==1 && !settings.swipeExit)){
-          --page; if (page<0) page=maxPage;
-          drawPage(page);
-      }
-  };
-  Bangle.on("swipe",swipeListenerDt);
-  
-  let isTouched = function(p,n){
-      if (n<0 || n>3) return false;
-      let x1 = (n%2)*72+XOFF;  let y1 =  n>1?72+YOFF:YOFF;
-      let x2 = x1+71; let y2 = y1+81;
-      return (p.x>x1 && p.y>y1 && p.x=0 || settings.direct) {
-                      if (selected!=i && !settings.direct){
-                          drawIcon(page,selected,false);
-                      } else {
-                          load(apps[page*4+i].src);
-                      }
-                  }
-                  selected=i;
-                  break;
-              }
-          }
-      }
-      if ((i==4 || (page*4+i)>Napps) && selected>=0) {
-          drawIcon(page,selected,false);
-          selected=-1;
-      }
-  };
-  Bangle.on("touch",touchListenerDt);
-    
-  const returnToClock = function() {
-    Bangle.setUI();
-    clearWatch(buttonWatch);
-    delete buttonWatch;
-    clearTimeout(timeoutToClock);
-    delete timeoutToClock;
-    delete s;
-    delete a;
-    delete n;
-    delete Napps;
-    delete Npages;
-    delete maxPage;
-    delete selected;
-    delete oldselected;
-    delete page;
-    delete XOFF;
-    delete YOFF;
-    delete x;
-    delete y;
-    delete txt;
-    delete lineY;
-    delete line;
-    delete c;
-    delete O;
-    delete x1;
-    delete x2;
-    delete i;
-    delete drawIcon;
-    delete drawPage;
-    delete isTouched;
-    Bangle.removeListener("swipe", swipeListenerDt);
-    delete swipeListenerDt;
-    Bangle.removeListener("touch", touchListenerDt);
-    delete touchListenerDt;
-    var apps = [];
-    delete apps;
-    delete returnToClock;
-    delete settings;
-    setTimeout(eval, 0, s.read(".bootcde"));
-  };
+Bangle.loadWidgets();
+//g.clear();
+Bangle.drawWidgets();
+drawPage(0);
+
+let swipeListenerDt = function(dirLeftRight, dirUpDown){
+    selected = 0;
+    oldselected=-1;
+    if(settings.swipeExit && dirLeftRight==1) returnToClock();
+    if (dirUpDown==-1||dirLeftRight==-1){
+        ++page; if (page>maxPage) page=0;
+        drawPage(page);
+    } else if (dirUpDown==1||(dirLeftRight==1 && !settings.swipeExit)){
+        --page; if (page<0) page=maxPage;
+        drawPage(page);
+    }
+};
+Bangle.on("swipe",swipeListenerDt);
+
+let isTouched = function(p,n){
+    if (n<0 || n>3) return false;
+    let x1 = (n%2)*72+XOFF;  let y1 =  n>1?72+YOFF:YOFF;
+    let x2 = x1+71; let y2 = y1+81;
+    return (p.x>x1 && p.y>y1 && p.x=0 || settings.direct) {
+                    if (selected!=i && !settings.direct){
+                        drawIcon(page,selected,false);
+                    } else {
+                        load(apps[page*4+i].src);
+                    }
+                }
+                selected=i;
+                break;
+            }
+        }
+    }
+    if ((i==4 || (page*4+i)>Napps) && selected>=0) {
+        drawIcon(page,selected,false);
+        selected=-1;
+    }
+};
+Bangle.on("touch",touchListenerDt);
   
+const returnToClock = function() {
+  Bangle.setUI();
+  clearWatch(buttonWatch);
+  delete buttonWatch;
+  clearTimeout(timeoutToClock);
+  delete timeoutToClock;
+  delete s;
+  delete a;
+  delete n;
+  delete Napps;
+  delete Npages;
+  delete maxPage;
+  delete selected;
+  delete oldselected;
+  delete page;
+  delete XOFF;
+  delete YOFF;
+  delete x;
+  delete y;
+  delete txt;
+  delete lineY;
+  delete line;
+  delete c;
+  delete O;
+  delete x1;
+  delete x2;
+  delete i;
+  delete drawIcon;
+  delete drawPage;
+  delete isTouched;
+  Bangle.removeListener("swipe", swipeListenerDt);
+  delete swipeListenerDt;
+  Bangle.removeListener("touch", touchListenerDt);
+  delete touchListenerDt;
+  var apps = [];
+  delete apps;
+  delete returnToClock;
+  delete settings;
+  setTimeout(eval, 0, s.read(".bootcde"));
+};
+
 } // end of app scope

From 479f0e3d6954be4ba9cad29dce12a72819ce0431 Mon Sep 17 00:00:00 2001
From: thyttan <6uuxstm66@mozmail.com⁩>
Date: Sun, 6 Nov 2022 19:59:04 +0100
Subject: [PATCH 129/179] comment in settings-b2.js

---
 apps/dtlaunch/settings-b2.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/dtlaunch/settings-b2.js b/apps/dtlaunch/settings-b2.js
index 315974c77..6d4c98c38 100644
--- a/apps/dtlaunch/settings-b2.js
+++ b/apps/dtlaunch/settings-b2.js
@@ -54,7 +54,7 @@
         writeSettings();
       }
     },
-    /*LANG*/'Time Out': {
+    /*LANG*/'Time Out': { // Adapted from Icon Launcher
       value: timeOutChoices.indexOf(settings.timeOut),
       min: 0,
       max: timeOutChoices.length-1,

From 675953ddcdc414483d74668bcdf00da5396163ce Mon Sep 17 00:00:00 2001
From: thyttan <6uuxstm66@mozmail.com⁩>
Date: Sun, 6 Nov 2022 20:20:51 +0100
Subject: [PATCH 130/179] make timeout to clock work

---
 apps/dtlaunch/app-b2.js      | 13 +++++++------
 apps/dtlaunch/settings-b2.js |  6 +++---
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js
index 7c75f291b..80ee36eca 100644
--- a/apps/dtlaunch/app-b2.js
+++ b/apps/dtlaunch/app-b2.js
@@ -15,13 +15,8 @@ let settings = Object.assign({
 
 if (settings.oneClickExit) {
   var buttonWatch = setWatch(_=> returnToClock, BTN1);
-} 
-
-// taken from Icon Launcher with minor alterations
-if (settings.timeOut!="Off"){
-  let time=parseInt(settings.timeOut);  //the "s" will be trimmed by the parseInt
-  var timeoutToClock = setTimeout(returnToClock,time*1000);  
 }
+
 let s = require("Storage");
   var apps = s.list(/\.info$/).map(app=>{
   let a=s.readJSON(app,1);
@@ -186,4 +181,10 @@ const returnToClock = function() {
   setTimeout(eval, 0, s.read(".bootcde"));
 };
 
+// taken from Icon Launcher with minor alterations
+if (settings.timeOut!="Off"){
+  let time=parseInt(settings.timeOut);  //the "s" will be trimmed by the parseInt
+  var timeoutToClock = setTimeout(returnToClock,time*1000);  
+}
+
 } // end of app scope
diff --git a/apps/dtlaunch/settings-b2.js b/apps/dtlaunch/settings-b2.js
index 6d4c98c38..80ad0414a 100644
--- a/apps/dtlaunch/settings-b2.js
+++ b/apps/dtlaunch/settings-b2.js
@@ -59,10 +59,10 @@
       min: 0,
       max: timeOutChoices.length-1,
       format: v => timeOutChoices[v],
-      onchange: m => {
-        settings.timeOut = m;
+      onchange: v => {
+        settings.timeOut = timeOutChoices[v];
         writeSettings();
       }
     },
   });
-})
+});

From 23a0c2fc2f6881de4aa11aec3febeb7cf8d39f83 Mon Sep 17 00:00:00 2001
From: thyttan <6uuxstm66@mozmail.com⁩>
Date: Sun, 6 Nov 2022 20:25:36 +0100
Subject: [PATCH 131/179] add to changelog

---
 apps/dtlaunch/ChangeLog | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/apps/dtlaunch/ChangeLog b/apps/dtlaunch/ChangeLog
index 05a1637c0..1054aa387 100644
--- a/apps/dtlaunch/ChangeLog
+++ b/apps/dtlaunch/ChangeLog
@@ -14,4 +14,5 @@
 0.14: Don't move pages when doing exit swipe - Bangle 2.
 0.15: 'Swipe to exit'-code is slightly altered to be more reliable - Bangle 2.
 0.16: Use default Bangle formatter for booleans
-0.17: Bangle 2: Fast loading on exit to clock face
+0.17: Bangle 2: Fast loading on exit to clock face. Added option for exit to
+clock face by timeout.

From ef1cf7ef7b3d2eecf11ea701fe2fdc82fef7ca5b Mon Sep 17 00:00:00 2001
From: thyttan <6uuxstm66@mozmail.com⁩>
Date: Sun, 6 Nov 2022 21:27:40 +0100
Subject: [PATCH 132/179] update timeout to clock per new implementation in
 Icon Launcher

---
 apps/dtlaunch/app-b2.js | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js
index 80ee36eca..11ef7ba5f 100644
--- a/apps/dtlaunch/app-b2.js
+++ b/apps/dtlaunch/app-b2.js
@@ -24,7 +24,7 @@ let s = require("Storage");
     name:a.name, type:a.type, icon:a.icon, sortorder:a.sortorder, src:a.src
   };}).filter(
     app=>app && (app.type=="app" || (app.type=="clock" && settings.showClocks) || (app.type=="launch" && settings.showLaunchers) || !app.type));
-  
+
 apps.sort((a,b)=>{
   let n=(0|a.sortorder)-(0|b.sortorder);
   if (n) return n; // do sortorder first
@@ -88,7 +88,7 @@ let drawPage = function(p){
     }
     g.flip();
 };
-  
+
 Bangle.loadWidgets();
 //g.clear();
 Bangle.drawWidgets();
@@ -139,7 +139,7 @@ let touchListenerDt = function(_,p){
     }
 };
 Bangle.on("touch",touchListenerDt);
-  
+
 const returnToClock = function() {
   Bangle.setUI();
   clearWatch(buttonWatch);
@@ -182,9 +182,14 @@ const returnToClock = function() {
 };
 
 // taken from Icon Launcher with minor alterations
-if (settings.timeOut!="Off"){
-  let time=parseInt(settings.timeOut);  //the "s" will be trimmed by the parseInt
-  var timeoutToClock = setTimeout(returnToClock,time*1000);  
-}
+var timeoutToClock;
+const updateTimeoutToClock = function(){
+  if (settings.timeOut!="Off"){
+    let time=parseInt(settings.timeOut);  //the "s" will be trimmed by the parseInt
+    if (timeoutToClock) clearTimeout(timeoutToClock);
+    timeoutToClock = setTimeout(returnToClock,time*1000);  
+  }
+};
+updateTimeoutToClock();
 
 } // end of app scope

From e0073bd17f355e44a7113ec060b287d352d5d1f6 Mon Sep 17 00:00:00 2001
From: thyttan <6uuxstm66@mozmail.com⁩>
Date: Sun, 6 Nov 2022 21:53:41 +0100
Subject: [PATCH 133/179] remove some delete statements, make BTN1 to clock
 work

---
 apps/dtlaunch/app-b2.js | 41 +++++++++--------------------------------
 1 file changed, 9 insertions(+), 32 deletions(-)

diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js
index 11ef7ba5f..48d9b2f38 100644
--- a/apps/dtlaunch/app-b2.js
+++ b/apps/dtlaunch/app-b2.js
@@ -14,7 +14,7 @@ let settings = Object.assign({
 }, require('Storage').readJSON("dtlaunch.json", true) || {});
 
 if (settings.oneClickExit) {
-  var buttonWatch = setWatch(_=> returnToClock, BTN1);
+  var buttonWatch = setWatch(_=> returnToClock(), BTN1, {edge: 'falling'});
 }
 
 let s = require("Storage");
@@ -142,42 +142,19 @@ Bangle.on("touch",touchListenerDt);
 
 const returnToClock = function() {
   Bangle.setUI();
-  clearWatch(buttonWatch);
-  delete buttonWatch;
-  clearTimeout(timeoutToClock);
-  delete timeoutToClock;
-  delete s;
-  delete a;
-  delete n;
-  delete Napps;
-  delete Npages;
-  delete maxPage;
-  delete selected;
-  delete oldselected;
-  delete page;
-  delete XOFF;
-  delete YOFF;
-  delete x;
-  delete y;
-  delete txt;
-  delete lineY;
-  delete line;
-  delete c;
-  delete O;
-  delete x1;
-  delete x2;
-  delete i;
-  delete drawIcon;
-  delete drawPage;
-  delete isTouched;
+  if (buttonWatch) {
+    clearWatch(buttonWatch);
+    delete buttonWatch;
+  }
+  if (timeoutToClock) {
+    clearTimeout(timeoutToClock);
+    delete timeoutToClock;
+  }
   Bangle.removeListener("swipe", swipeListenerDt);
-  delete swipeListenerDt;
   Bangle.removeListener("touch", touchListenerDt);
-  delete touchListenerDt;
   var apps = [];
   delete apps;
   delete returnToClock;
-  delete settings;
   setTimeout(eval, 0, s.read(".bootcde"));
 };
 

From 351ce5f891b7d4db87a7360f2c9e2592537a1dca Mon Sep 17 00:00:00 2001
From: thyttan <6uuxstm66@mozmail.com⁩>
Date: Mon, 7 Nov 2022 00:07:27 +0100
Subject: [PATCH 134/179] exit by pressing upper left corner of screen

---
 apps/calculator/ChangeLog     | 1 +
 apps/calculator/README.md     | 8 ++++++++
 apps/calculator/app.js        | 4 ++++
 apps/calculator/metadata.json | 2 +-
 4 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/apps/calculator/ChangeLog b/apps/calculator/ChangeLog
index f3ce3a928..2e1ace7bf 100644
--- a/apps/calculator/ChangeLog
+++ b/apps/calculator/ChangeLog
@@ -4,3 +4,4 @@
 0.04: Display current operation on LHS
 0.05: Grid positioning and swipe controls to switch between numbers, operators and special (for Bangle.js 2)
 0.06: Bangle.js 2: Exit with a short press of the physical button
+0.07: Bangle.js 2: Exit by pressing upper left corner of the screen
diff --git a/apps/calculator/README.md b/apps/calculator/README.md
index b25d355bf..8681965f2 100644
--- a/apps/calculator/README.md
+++ b/apps/calculator/README.md
@@ -12,12 +12,20 @@ Basic calculator reminiscent of MacOs's one. Handy for small calculus.
 
 ## Controls
 
+Bangle.js 1
 - UP: BTN1
 - DOWN: BTN3
 - LEFT: BTN4
 - RIGHT: BTN5
 - SELECT: BTN2
 
+Bangle.js 2
+- Swipes to change visible buttons
+- Click physical button exit
+- Press upper left corner of screen to exit (where the red back button would be)
 ## Creator
 
 
+
+## Contributors
+[thyttan](https://github.com/thyttan)
diff --git a/apps/calculator/app.js b/apps/calculator/app.js
index 571a5b27f..f31b591ad 100644
--- a/apps/calculator/app.js
+++ b/apps/calculator/app.js
@@ -402,6 +402,10 @@ if (process.env.HWVERSION==1) {
   swipeEnabled = false;
   drawGlobal();
 } else { // touchscreen?
+  Bangle.setUI({ // Pressing upper left corner turns off (where red back button would be)
+    mode : 'custom',
+    back : load
+  });
   setWatch(_ => {load();}, BTN1, {edge:'falling'}); // Exit with a short press to physical button
   selected = "NONE";
   swipeEnabled = true;
diff --git a/apps/calculator/metadata.json b/apps/calculator/metadata.json
index 536a6955e..1674b7843 100644
--- a/apps/calculator/metadata.json
+++ b/apps/calculator/metadata.json
@@ -2,7 +2,7 @@
   "id": "calculator",
   "name": "Calculator",
   "shortName": "Calculator",
-  "version": "0.06",
+  "version": "0.07",
   "description": "Basic calculator reminiscent of MacOs's one. Handy for small calculus.",
   "icon": "calculator.png",
   "screenshots": [{"url":"screenshot_calculator.png"}],

From 1ad66dd16ef58558418ad5cce7effcae91126c6f Mon Sep 17 00:00:00 2001
From: Gordon Williams 
Date: Mon, 7 Nov 2022 09:22:36 +0000
Subject: [PATCH 135/179] Misc tweaks - and linking to privacy policy for
 collected data

---
 bin/firmwaremaker_c.js | 2 +-
 core                   | 2 +-
 index.html             | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/bin/firmwaremaker_c.js b/bin/firmwaremaker_c.js
index 87065dab4..e56e28ad9 100755
--- a/bin/firmwaremaker_c.js
+++ b/bin/firmwaremaker_c.js
@@ -172,7 +172,7 @@ Promise.all(APPS.map(appid => {
 // Generated by BangleApps/bin/build_bangles_c.js
 
 const int jsfStorageInitialContentLength = ${storageContent.length};
-const char jsfStorageInitialContents[] = {
+const unsigned char jsfStorageInitialContents[] = {
 `;
 for (var i=0;i
           
           
+ Send app analytics to banglejs.com +
- Send app analytics to banglejs.com + Send favourite and installed apps to banglejs.com
+ For 'Sort by Installed/Favourited' functionality
`; showPrompt("Which Bangle.js?",html,{},false); + var usageStats = document.getElementById("usage_stats"); + usageStats.addEventListener("change",event=>{ + console.log("Send Usage Stats "+(event.target.checked?"on":"off")); + SETTINGS.sendUsageStats = event.target.checked; + saveSettings(); + }); htmlToArray(document.querySelectorAll(".devicechooser")).forEach(button => { button.addEventListener("click",event => { let rememberDevice = !!document.getElementById("remember_device").checked; - SETTINGS.sendUsageStats = !!document.getElementById("usage_stats").checked; - let button = event.currentTarget; let deviceId = button.getAttribute("deviceid"); hidePrompt(); From b3ba5d828f196c58c42471deab5e9517a1726365 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 7 Nov 2022 14:45:33 +0000 Subject: [PATCH 142/179] link in priv policy --- loader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader.js b/loader.js index c0cd15de5..9b337223b 100644 --- a/loader.js +++ b/loader.js @@ -162,7 +162,7 @@ window.addEventListener('load', (event) => {