diff --git a/apps/quarterclock/app-icon.js b/apps/quarterclock/app-icon.js new file mode 100644 index 000000000..d6ed783ec --- /dev/null +++ b/apps/quarterclock/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4X/AwX48AFCqoAEC4oL/Bf4L/Bf4LTAH4A/ADGqAAIL/Bf4LD")) diff --git a/apps/quarterclock/app.js b/apps/quarterclock/app.js new file mode 100644 index 000000000..da7efed16 --- /dev/null +++ b/apps/quarterclock/app.js @@ -0,0 +1,139 @@ +{ + const minute_boxes = [ + {x:0.5, y:0}, + {x:0.5, y:0.5}, + {x:0, y:0.5}, + {x:0, y:0}, + ]; + + const hour_boxes = [ + {x:0.5, y:0}, + {x:0.75, y:0}, + {x:0.75, y:0.25}, + {x:0.75, y:0.5}, + {x:0.75, y:0.75}, + {x:0.5, y:0.75}, + {x:0.25, y:0.75}, + {x:0, y:0.75}, + {x:0, y:0.5}, + {x:0, y:0.25}, + {x:0, y:0}, + {x:0.25, y:0}, + ]; + + let drawTimeout; + + // schedule a draw for the next 15 minute period + let queueDraw = function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, (60000 * 15) - (Date.now() % (60000 * 15))); + }; + + // Main draw function + let draw = function draw() { + var d = new Date(); + var h = d.getHours(), m = d.getMinutes(); + + g.setBgColor(settings.backgroundColour); + g.clearRect(Bangle.appRect); + + if (settings.showBattery) { + drawBattery(); + } + + // Draw minute box + drawBox(Math.floor(m/15), minute_boxes, Bangle.appRect.h/2, settings.minuteColour); + + // Draw an hour box or write the number + if (settings.digital) { + g.setColor(settings.hourColour); + g.setFont("Vector:60"); + g.setFontAlign(0,0); + g.drawString(h, Bangle.appRect.x + Bangle.appRect.w/2, Bangle.appRect.y + Bangle.appRect.h/2); + } else { + drawBox(h % 12, hour_boxes, Bangle.appRect.h/4, settings.hourColour); + } + + queueDraw(); + }; + + // Draw battery box + let drawBattery = function drawBattery() { + // Round battery up to 10% interval + let battery = (Math.floor(E.getBattery()/10)+1)/10; + + // Maximum battery box + let batterySize = 30; + + // Draw outer box at full brightness + g.setColor(settings.batteryColour); + g.drawRect( + (Bangle.appRect.w / 2) - batterySize, + (Bangle.appRect.h / 2) - batterySize + Bangle.appRect.y, + (Bangle.appRect.w / 2) + batterySize, + (Bangle.appRect.h / 2) + batterySize + Bangle.appRect.y + ); + + // Fade battery colour and draw inner box + g.setColor(settings.batteryColour.split('').map((c) => { + return c=='f' ? Math.ceil(15 * battery).toString(16) : c; + }).join('')); + g.fillRect( + (Bangle.appRect.w / 2) - (batterySize * battery), + (Bangle.appRect.h / 2) - (batterySize * battery) + Bangle.appRect.y, + (Bangle.appRect.w / 2) + (batterySize * battery), + (Bangle.appRect.h / 2) + (batterySize * battery) + Bangle.appRect.y + ); + }; + + // Draw hour or minute boxes + let drawBox = function drawBox(current, boxes, size, colour) { + x1 = (boxes[current].x * Bangle.appRect.h) + (Bangle.appRect.y/2); + y1 = (boxes[current].y * Bangle.appRect.h) + Bangle.appRect.y; + x2 = x1 + size; + y2 = y1 + size; + g.setColor(colour); + g.fillRect(x1, y1, x2, y2); + }; + + let settings = Object.assign({ + // Default values + minuteColour: '#f00', + hourColour: '#ff0', + backgroundColour: 'theme', + showWidgets: true, + showBattery: true, + digital: false, + batteryColour: '#0f0' + }, require('Storage').readJSON('quarterclock.json', true) || {}); + + if (settings.backgroundColour == 'theme') { + settings.backgroundColour = g.theme.bg; + } + + // Set minuteColour to a darker shade if same as hourColour + if (settings.minuteColour == settings.hourColour) { + settings.minuteColour = settings.minuteColour.split('').map((c) => { + return c=='f' ? '7' : c; + }).join(''); + } + + // Show launcher when middle button pressed + // Remove handler to allow fast loading + Bangle.setUI({mode:"clock", remove:function() { + if (drawTimeout) clearTimeout(drawTimeout); + }}); + + // Load and display widgets + if (settings.showWidgets) { + Bangle.loadWidgets(); + Bangle.drawWidgets(); + } + + // draw initial boxes and queue subsequent redraws + draw(); +} + diff --git a/apps/quarterclock/app.png b/apps/quarterclock/app.png new file mode 100644 index 000000000..e2a1c7fc0 Binary files /dev/null and b/apps/quarterclock/app.png differ diff --git a/apps/quarterclock/metadata.json b/apps/quarterclock/metadata.json new file mode 100644 index 000000000..9ce2bce18 --- /dev/null +++ b/apps/quarterclock/metadata.json @@ -0,0 +1,20 @@ +{ + "id": "quarterclock", + "name": "Quarter Clock", + "shortName":"Quarter Clock", + "icon": "app.png", + "screenshots" : [ { "url":"screenshot.png" } ], + "version":"0.01", + "description": "For those lazy days when the exact time doesn't matter. Small square shows the hour, large square shows the fifteen minute period, and centre square shows the battery level.", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS2"], + "storage": [ + {"name":"quarterclock.app.js","url":"app.js"}, + {"name":"quarterclock.settings.js","url":"settings.js"}, + {"name":"quarterclock.img","url":"app-icon.js","evaluate":true} + ], + "data": [ + {"name":"quarterclock.json"} + ] +} diff --git a/apps/quarterclock/screenshot.png b/apps/quarterclock/screenshot.png new file mode 100644 index 000000000..f1741f4ca Binary files /dev/null and b/apps/quarterclock/screenshot.png differ diff --git a/apps/quarterclock/settings.js b/apps/quarterclock/settings.js new file mode 100644 index 000000000..892e82cfd --- /dev/null +++ b/apps/quarterclock/settings.js @@ -0,0 +1,66 @@ +(function(back) { + var FILE = 'quarterclock.json'; + // Load settings + var settings = Object.assign({ + minuteColour: '#f00', + hourColour: '#ff0', + backgroundColour: 'theme', + showWidgets: true, + showBattery: true, + digital: false, + batteryColour: '#0f0', + }, require('Storage').readJSON(FILE, true) || {}); + + function setSetting(key,value) { + settings[key] = value; + require('Storage').writeJSON(FILE, settings); + } + + // Helper method which uses int-based menu item for set of string values and their labels + function stringItems(key, startvalue, values, labels) { + return { + value: (startvalue === undefined ? 0 : values.indexOf(startvalue)), + format: v => labels[v], + min: 0, + max: values.length - 1, + wrap: true, + step: 1, + onchange: v => { + setSetting(key,values[v]); + } + }; + } + + // Helper method which breaks string set settings down to local settings object + function stringInSettings(name, values, labels) { + return stringItems(name,settings[name], values, labels); + } + + // Show the menu + E.showMenu({ + '' : { 'title' : 'Quarter Clock' }, + '< Back' : () => back(), + 'Hour Colour': stringInSettings('hourColour', ['#f00', '#0f0', '#00f', '#ff0', '#0ff', '#f0f'], ['Red', 'Green', 'Blue', 'Yellow', 'Cyan', 'Magenta']), + 'Minute Colour': stringInSettings('minuteColour', ['#f00', '#0f0', '#00f', '#ff0', '#0ff', '#f0f'], ['Red', 'Green', 'Blue', 'Yellow', 'Cyan', 'Magenta']), + 'Background Colour': stringInSettings('backgroundColour', ['theme', '#000', '#fff'],['theme', 'Black', 'White']), + 'Digital': { + value: !!settings.digital, // !! converts undefined to false + onchange: v => { + setSetting('digital', v); + }, + }, + 'Show Widgets': { + value: !!settings.showWidgets, + onchange: v => { + setSetting('showWidgets', v); + }, + }, + 'Show Battery': { + value: !!settings.showBattery, + onchange: v => { + setSetting('showBattery', v); + }, + }, + 'Battery Colour': stringInSettings('batteryColour', ['#f00', '#0f0', '#00f', '#ff0', '#0ff', '#f0f'], ['Red', 'Green', 'Blue', 'Yellow', 'Cyan', 'Magenta']), + }); +})