From 298df7b877e33e98877448dac9aff99ec30408fb Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 29 Jan 2023 15:55:49 +0100 Subject: [PATCH] Added happy clock --- apps/happyclk/ChangeLog | 1 + apps/happyclk/README.md | 10 ++ apps/happyclk/happyclk.app.js | 170 +++++++++++++++++++++++++++++++++ apps/happyclk/happyclk.icon.js | 1 + apps/happyclk/happyclk.png | Bin 0 -> 469 bytes apps/happyclk/metadata.json | 20 ++++ apps/happyclk/screenshot_1.png | Bin 0 -> 2547 bytes apps/happyclk/screenshot_2.png | Bin 0 -> 2554 bytes 8 files changed, 202 insertions(+) create mode 100644 apps/happyclk/ChangeLog create mode 100644 apps/happyclk/README.md create mode 100644 apps/happyclk/happyclk.app.js create mode 100644 apps/happyclk/happyclk.icon.js create mode 100644 apps/happyclk/happyclk.png create mode 100644 apps/happyclk/metadata.json create mode 100644 apps/happyclk/screenshot_1.png create mode 100644 apps/happyclk/screenshot_2.png diff --git a/apps/happyclk/ChangeLog b/apps/happyclk/ChangeLog new file mode 100644 index 000000000..759f68777 --- /dev/null +++ b/apps/happyclk/ChangeLog @@ -0,0 +1 @@ +0.01: New app! \ No newline at end of file diff --git a/apps/happyclk/README.md b/apps/happyclk/README.md new file mode 100644 index 000000000..e7f0cefa9 --- /dev/null +++ b/apps/happyclk/README.md @@ -0,0 +1,10 @@ +# Happy Clock + +A really happy clock. + +The left eye shows the hour, the right hour the minutes. +The mouth the battery percentage, each eyebrow shows 5k steps. +The left mouthline shows whether your bangle is locked or not and the right whether its connected via bluetooth or not. + +## Creator +- [David Peer](https://github.com/peerdavid). \ No newline at end of file diff --git a/apps/happyclk/happyclk.app.js b/apps/happyclk/happyclk.app.js new file mode 100644 index 000000000..aeefa499e --- /dev/null +++ b/apps/happyclk/happyclk.app.js @@ -0,0 +1,170 @@ +/************************************************ + * Happy Clock + */ +var W = g.getWidth(),R=W/2; +var H = g.getHeight(); +var drawTimeout; + + +/* + * Based on the great multi clock from https://github.com/jeffmer/BangleApps/ + */ +Graphics.prototype.drawRotRect = function(cx, cy, r1, r2, angle) { + angle = angle % 360; + var theta=angle*Math.PI/180; + var x = parseInt(cx+r1*Math.sin(theta)*1.2); + var y = parseInt(cy-r1*Math.cos(theta)*1.2); + + g.setColor(g.theme.fg); + g.fillCircle(cx, cy, 32); + g.setColor(g.theme.bg); + g.fillCircle(cx, cy, 28); + + g.setColor(g.theme.fg); + g.fillCircle(x, y, 12); +}; + +let drawEyes = function(){ + // And now the analog time + var drawHourHand = g.drawRotRect.bind(g,55,70,12,R-38); + var drawMinuteHand = g.drawRotRect.bind(g,125,70,12,R-12); + + g.setFontAlign(0,0); + + // Compute angles + var date = new Date(); + var m = parseInt(date.getMinutes() * 360 / 60); + var h = date.getHours(); + h = h > 12 ? h-12 : h; + h += date.getMinutes()/60.0; + h = parseInt(h*360/12); + + // Draw minute and hour fg + g.setColor(g.theme.fg); + drawHourHand(h); + drawMinuteHand(m); +} + +function quadraticCurve(t, p0x, p0y, p1x, p1y, p2x, p2y){ + var t2 = t * t; + var oneMinT = 1 - t; + var oneMinT2 = oneMinT * oneMinT; + return { + x: p0x * oneMinT2 + 2 * p1x * t * oneMinT + p2x *t2, + y: p0y * oneMinT2 + 2 * p1y * t * oneMinT + p2y *t2 + }; +} + +let drawSmile = function(isLocked){ + var w = 8; + var y = 120; + var o = parseInt(E.getBattery()*0.8); + + var isConnected = NRF.getSecurityStatus().connected; + for(var i = 0; i < w; i++){ + drawCurve(30, y+i, W/2+10, y+i+o, W-40, y+i); + } + + for(var i=0; i < w-2; i++){ + if(isLocked) g.drawLine(25, y+5+i, 35, y-5+i); + if(isConnected) g.drawLine(W-35, y+5+i, W-45, y-5+i); + } +} + +let drawEyeBrow = function(){ + var w = 4; + var steps = Bangle.getHealthStatus("day").steps; + var reached = steps / 10000.0; + reached = 1.1; + for(var i = 0; i < w; i++){ + if(reached > 0.5) g.drawLine(25, 25+i, 70, 15+i); + if(reached > 1.0) g.drawLine(W-25, 25+i, W-70, 15+i); + } +} + +// Thanks to user stephaneAG from the Espruino forum! +// https://forum.espruino.com/conversations/330154/#comment14593349 +let drawCurve = function(x1, y1, x2, y2, x3, y3){ + var p0 = { x: x1, y: y1}; + var p1 = { x: x2, y: y2}; + var p2 = { x: x3, y: y3}; + var time = 0; + //var stepping = 0.005; // seems the nicest + //var stepping = 0.05; // a little less neat, yet faster + var stepping = 0.1; // quick enough ? + var pathPts = []; + for(time = 0; time <= 1; time+= stepping){ + var pos = quadraticCurve(time, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y); + pathPts.push(pos.x, pos.y); + } + g.drawPoly(pathPts, false); + g.flip(); +} + + +let draw = function(){ + // Queue draw in one minute + queueDraw(); + + var isLocked = Bangle.isLocked(); + drawHelper(isLocked); +} + +let drawHelper = function(isLocked){ + g.setColor(g.theme.fg); + g.reset().clear(); + + drawEyes(); + drawSmile(isLocked); + drawEyeBrow(); +} + + +/* + * Listeners + */ +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); + +Bangle.on('lock', function(isLocked) { + draw(isLocked); +}); + + +/* + * Some helpers + */ +let queueDraw = function() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); +} + + +/* + * Lets start widgets, listen for btn etc. + */ +// Show launcher when middle button pressed +Bangle.setUI("clock"); +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. + */ +require('widget_utils').hide(); + +// Clear the screen once, at startup and draw clock +// g.setTheme({bg:"#fff",fg:"#000",dark:false}); +draw(); + +// After drawing the watch face, we can draw the widgets +// Bangle.drawWidgets(); diff --git a/apps/happyclk/happyclk.icon.js b/apps/happyclk/happyclk.icon.js new file mode 100644 index 000000000..d59fc0668 --- /dev/null +++ b/apps/happyclk/happyclk.icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgP/ADEP/AEC+E//kH//+gYIB8F//1/B4U/ERgdB/wdB//AFIJGCx/n+P8EIM/+fnE4IBB/PAv4aBv/84E/z/8//8wAFDwwFB74FBgQFD/wFGyF/AoUAz//z/+AoPfAoV/gPP/+/IIP585lCj/z8ZvCw+H/HwPQUf/iACACIrBAAaRCGAP+AoXzAonxAoJRB//lAQJLBC4X/44IE8KeCVoQCBj4CB/iYBEwX+h6sCAAOB8BCD4C+CDwTKCACI=")) \ No newline at end of file diff --git a/apps/happyclk/happyclk.png b/apps/happyclk/happyclk.png new file mode 100644 index 0000000000000000000000000000000000000000..53fbe152ef305866412f0523c6088c97183854bb GIT binary patch literal 469 zcmV;`0V@89P)D=yD>gz z8<52-;B0)e1S0bH-xE^%cd{WU(I6fTMh($;qFhS>tV!I)0M2o3p{kR1Hjjuj5m9Xj zZ=tKg=;Tx`j{xtv-N$*xu*R7&us6!m+MjD4Mz~D-Jb3_3Qv3JN zoMPE<$SGv4#0ZZ#ZHy`a_5O-6K6dA|;^GPz|M}gtiqj z+b!MDXs9STT3f6@RS;(3&criBvuP$~;C=u(7PWVnTpjKpj%HPFp_b-~R--e*=*`5c z(hPG&T1v}v$kxbmy*=^Sc!q#0)I1teiHwbXIqt<$K(*(iom^`djsdR-Qvl)>6iBJD z6wrw(MT~P>2ydaIM4-L2Tflh7!xWO?3atRMzMpYG-5Od8A>YPU9B4@fAEUF?h^z?f zLm#CY^)~RcaphkrRU#lB7*o@(RU)~9*@DpTg{u3b%hp0(++M&BTNMyXm!1(>00000 LNkvXXu0mjf7L3kJ literal 0 HcmV?d00001 diff --git a/apps/happyclk/metadata.json b/apps/happyclk/metadata.json new file mode 100644 index 000000000..51028df4b --- /dev/null +++ b/apps/happyclk/metadata.json @@ -0,0 +1,20 @@ +{ + "id": "happyclk", + "name": "Happy Clock", + "shortName":"Happy Clock", + "icon": "happyclk.png", + "version":"0.01", + "readme": "README.md", + "supports": ["BANGLEJS2"], + "description": ":)", + "type": "clock", + "tags": "clock", + "screenshots": [ + {"url":"screenshot_1.png"}, + {"url":"screenshot_2.png"}, + ], + "storage": [ + {"name":"happyclk.app.js","url":"happyclk.app.js"}, + {"name":"happyclk.img","url":"happyclk.icon.js","evaluate":true} + ] +} diff --git a/apps/happyclk/screenshot_1.png b/apps/happyclk/screenshot_1.png new file mode 100644 index 0000000000000000000000000000000000000000..879b01cbf34ada7ef948777cfa587ab2b27c29d5 GIT binary patch literal 2547 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 MjjRkQ`nb6N0>e(3S^xk5 literal 0 HcmV?d00001 diff --git a/apps/happyclk/screenshot_2.png b/apps/happyclk/screenshot_2.png new file mode 100644 index 0000000000000000000000000000000000000000..d561c3175c23a53563b29773c14a9e39dd73b689 GIT binary patch literal 2554 zcmbVOc{J1u8~)AD3`1fvM#jxp##rOCMngiFCdxVnS%$1hDc2ST@zBme-| zPdsVsx`!?Q1YC44H@AQC+XG0nE5Qb6dU@z80En}Qw$|?Pek;E(#V+CD>65~gFUcMw zg~l)1bge*9CF-;O{{BC^HwmyzZT@L$7QVNoQUXCqb@qmUKJP3=ov8g* z;V^hq__n+SL|ufAQs&TC&heq8l0_a=pyXlhQzXUke~>jccD99U8DE9M6PWBLWXG_} z!Hm{poJz`}AuE{t(U)OW?IN2}oH#q8J74?Mnk0ITPj zxK%yUDyXy5GonPEUDOoDMPIqOfx#tdVk?xJ;0dc5FuwtQH3STEOWo_%!S2OW& zGe6Y)d{Zvo5fig8q{yCbb4}|WX9VpY+6jX5qBXC^|oZ4(F2tygy)%EfQd4@vF*L0b) zc#fvc6uS7I0oX8lq+QT^BCI2oSnF1I-D}kDnkF5R6jC52c||J-+x2n7&%c;{&D~>4 z3kbzA+CL{{kbn3sH4P-P&e;Ee#(x^dP1Mp2Clj2{`4vhcZMO9`J2 zdl}(#ovF2jg>Xxw5R&CcjJ>oM=8>`w;pAG`@UDp|iUPeKYG-jLxIdhg0i8OBDK-mf z+blmm5I*J?01z;@8QgrP(cOvZqo@M3Up#KCUj`^{LHC%BbA4XH3ALT-14p?Ht$y^{hh7*tRqz^@$9ep z=P~0p@fy`cUIY`@+j?jPmc-l&nBt`67t-v*rCZd5FL(@Zj&h=lG;=+wva zGI_Y8q2HgBp?Iy*Gg6d&9SV8k{DcGfUsV5f{0X)ljEAvnPpKPZqT;6=2$KL?X2$%6 zxV}!yXGg>G6Vw#7g71P82Kz<8Ip;zpf&9H$QQebAqzn?Q*d3yB`D%i6FFmozz=q)n;v{D4rgsZ8zGz*{cM!IsdVpku!RT7ab7G`eo^Uw1D{ z)gcF5Dr8TX=4+J}q2d%cWJK+Z{o}{HwGNd0qY~=Sq{`d-e}X=+50Zt38>7#%5$Eun zFNn}PMURB=kRqNk(4A(+pm%g0UmiXZ_N~6V$G%7K4ry1?F6#0GX^O8QAP6*zt1UFq zp_h*>q6whqm7+v+2K<|#>eUT{b56wjX-rNfEjNApP(*#^%u+JQM$;9N-O$GP! zP&|nTY5_y?FKE?XDIrWzR$21PdDX9=bPKD|GhC*?x|XeKZU4_tnjxWw%MY;MVZ1sk zCe|}>IgFz?h+lw@7=@th*${2w>kU{K7E}sJR6w{Mn>7gM%N-G(F8Ke8D&QJB$#o^T z;7pPGsFLX1#9cS2*=pXsFAylFvU%sgToP63fV)6NaqgozgOvW_`QW96Ous+C^7Ulz zYw%IOM>R^}Ky6a1L*%D%d;j6Wy-i58$)Tpk8WNCFQ6{t~m$fWr0ihbGO>Qn$0@uk+ z;AMGE!Oy(Uits~xhU{Gg702&pV!3}K9Ddjc#HHp=nGUbHoK>Ph{nT<@foq4lu+`2v z{Pi1@=J=R@$*-#r%s91`;XAAnMDH`pt9i7|zT>i#ey28!E|zP6a9G7xb@7p+e8n3V zGy;{oCWGCRk1wcp#iGF$F2?4tOMhrKYin!SvRzw}lWPnYl$VXay|WlG{X7CA%Sq?G zm|u#~dA`m5y;mvW=5^8F-hsyF+fNUwa+q9$8|3Eh7Sv|&>^%+ptE#eTQ;&V|oPE+Q zf5;#MkBusNi*3q%h@ZV2gj9;pmfiZBjb!7r^(V#Ar6Vp-&xWGsW*gk-n%J~((pOqSU3gn9V^wEv`8Wh1JFXoYrn}$)M0|5*C*E7V z4n4MOFBWAQf3^)lfD%Gt8+r&|aPO;1Hi}xxkGI1F#P&R1oMw{D!@4 z%PZRE?77Bny2s`(?r&K?^BWgF^mP){epY5(lO`-(f%uVbb=_)+twz(uAeNe44GI}( z-WOtxoe`K+?G4K_iOhuMNJPW=9Gq>Q__yY8sHaQFg8=o8lp$4)1hrLf6Rx)^@{7Kr zlc1>&8n+D5;d^4=!1qr<$J7MTGLVN6y=B0jRRWOmslE{K!bFY{L{^ytsOv*JK`5_D zF%;CaqCy-g@K_kU#n=2L)R_v1lyVTudrh6O<>FNUL{y)q!rQY{u`6asE80&W%%