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 000000000..53fbe152e Binary files /dev/null and b/apps/happyclk/happyclk.png differ 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 000000000..879b01cbf Binary files /dev/null and b/apps/happyclk/screenshot_1.png differ diff --git a/apps/happyclk/screenshot_2.png b/apps/happyclk/screenshot_2.png new file mode 100644 index 000000000..d561c3175 Binary files /dev/null and b/apps/happyclk/screenshot_2.png differ