diff --git a/apps.json b/apps.json index 8f291d3b7..3e0ab4181 100644 --- a/apps.json +++ b/apps.json @@ -242,8 +242,8 @@ { "id": "sweepclock", "name": "Sweep Clock", "icon": "sweepclock.png", - "version":"0.02", - "description": "Smooth sweep secondhand with single hour numeral. Use button1 to toggle the numeral font and button3 to change the colour theme", + "version":"0.03", + "description": "Smooth sweep secondhand with single hour numeral. Use button1 to toggle the numeral font, button 3 to change the colour theme and button 4 to change the date placement", "tags": "clock", "type":"clock", "allow_emulator":true, @@ -3044,7 +3044,7 @@ "name": "Gadgetbridge Music Controls", "shortName":"Music Controls", "icon": "icon.png", - "version":"0.04", + "version":"0.05", "description": "Control the music on your Gadgetbridge-connected phone", "tags": "tools,bluetooth,gadgetbridge,music", "type":"app", @@ -3085,7 +3085,7 @@ { "id": "kitchen", "name": "Kitchen Combo", "icon": "kitchen.png", - "version":"0.08", + "version":"0.10", "description": "Combination of the Stepo, Walkersclock, Arrow and Waypointer apps into a multiclock format. 'Everything but the kitchen sink'. Requires firmware v2.08.167 or later", "tags": "tool,outdoors,gps", "type":"clock", @@ -3096,10 +3096,13 @@ {"name":"stepo.kit.js","url":"stepo.kit.js"}, {"name":"gps.kit.js","url":"gps.kit.js"}, {"name":"digi.kit.js","url":"digi.kit.js"}, + {"name":"heart.kit.js","url":"heart.kit.js"}, {"name":"swatch.kit.js","url":"swatch.kit.js"}, {"name":"compass.kit.js","url":"compass.kit.js"}, - {"name":"waypoints.json","url":"waypoints.json","evaluate":false}, {"name":"kitchen.img","url":"kitchen.icon.js","evaluate":true} + ], + "data": [ + {"name":"waypoints.json","url":"waypoints.json"} ] }, { "id": "qmsched", @@ -3152,7 +3155,7 @@ "id": "omnitrix", "name":"Omnitrix", "icon":"omnitrix.png", - "version": "1.0", + "version": "0.01", "readme": "README.md", "description": "An Omnitrix Showpiece", "tags": "game", @@ -3166,7 +3169,7 @@ "name": "Bat Clock", "shortName":"Bat Clock", "icon": "bat-clock.png", - "version":"1.0", + "version":"0.01", "description": "Morphing Clock, with an awesome \"The Dark Knight\" themed logo.", "tags": "clock", "type": "clock", @@ -3180,14 +3183,15 @@ "name":"Dozenal Time", "shortName":"Dozenal Time", "icon":"app.png", - "version":"1.0", + "version":"0.01", "description":"A dozenal Holocene calendar and dozenal diurnal clock", "tags":"clock", "type":"clock", "allow_emulator":true, + "readme": "README.md", "storage": [ {"name":"doztime.app.js","url":"app.js"}, {"name":"doztime.img","url":"app-icon.js","evaluate":true} ] } -] +] \ No newline at end of file diff --git a/apps/doztime/ChangeLog b/apps/doztime/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/doztime/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/doztime/README.md b/apps/doztime/README.md new file mode 100644 index 000000000..075b2f66a --- /dev/null +++ b/apps/doztime/README.md @@ -0,0 +1,14 @@ +Dozenal Time +============ + +A dozenal Holocene calendar and a dozenal diurnal clock. For information about them, go to https://dozenal.ae-web.ca/pdf/dozenal-calendar.pdf and https://dozenal.ae-web.ca/pdf/about-short.pdf. They've been in use for some years. + +In the dozenal number base, ten and eleven are single digits, and 10 is a dozen. The clock simply divides the day by successive powers of a dozen. The day or parts of it may be divided easily into halves, thirds, quarters, sixths, or twelfths (dozenths). There is no conglomeration of bases two, ten, twelve, and sixty, as in the current system of time measurement. + +The annual calendar has a dozen months of 5 weeks each, each week having 6 days. The 5 or 6 days beyond 360 (dozenal 260) are added where they keep the season beginnings the most accurate. + +The year itself begins on the December solstice. Because that always happens, there is no need of a leap-year rule to keep the seasons from drifting. + +The epoch (year numbering) begins in the last year when the perihelion coincided with the June solstice, near the beginning of the Holocene era. That astronomical basis makes the calendar free from politics, religion, or geography. + +While the year number remains cardinal, BTN5 toggles between cardinal and ordinal for the rest of the calendar segments. BTN4 adds or removes a quickly changing digit to or from the clock. diff --git a/apps/gbmusic/ChangeLog b/apps/gbmusic/ChangeLog index 99dd02116..ecbca5fb6 100644 --- a/apps/gbmusic/ChangeLog +++ b/apps/gbmusic/ChangeLog @@ -2,3 +2,4 @@ 0.02: Increase text brightness, improve controls, (try to) reduce memory usage 0.03: Only auto-start if active app is a clock, auto close after 1 hour of inactivity 0.04: Setting to disable touch controls, minor bugfix +0.05: Setting to disable double/triple press control, remove touch controls setting, reduce fadeout flicker \ No newline at end of file diff --git a/apps/gbmusic/README.md b/apps/gbmusic/README.md index d081e952f..4bad9b8c8 100644 --- a/apps/gbmusic/README.md +++ b/apps/gbmusic/README.md @@ -22,8 +22,9 @@ You can change these under `Settings`->`App/Widget Settings`->`Music Controls`. Automatically load the app when you play music and close when the music stops. (If the app opened automatically, it closes after music has been paused for 5 minutes.) -**Touch**: -Enable touch controls? +**Simple button**: +Disable double/triple pressing Button 2: always simply toggle play/pause. +(For music players which handle multiple button presses themselves.) ## Controls diff --git a/apps/gbmusic/app.js b/apps/gbmusic/app.js index 75c028b20..5f95868bb 100644 --- a/apps/gbmusic/app.js +++ b/apps/gbmusic/app.js @@ -13,10 +13,6 @@ let info = { }; const POUT = 300000; // auto close timeout when paused: 5 minutes (in ms) const IOUT = 3600000; // auto close timeout for inactivity: 1 hour (in ms) -// Touch controls? 0: off, 1: when LCD on, 2: always -let s = require("Storage").readJSON("gbmusic.json", 1) || {}; -const TCTL = ("touch" in s) ? (s.touch|0)%3 : 1; -delete s; /////////////////////// // Self-repeating timeouts @@ -42,7 +38,7 @@ function fadeOut() { if (!Bangle.isLCDOn() || !fade) { return; } - drawMusic(); + drawMusic(false); // don't clear: draw over existing text to prevent flicker setTimeout(fadeOut, 500); } function brightness() { @@ -131,7 +127,7 @@ function f2hex(f) { return ("00"+(Math.round(f*255)).toString(16)).substr(-2); } /** - * @param name + * @param {string} name - musicinfo property "num"/"artist"/"album"/"track" * @return {string} Semi-random color to use for given info */ function infoColor(name) { @@ -174,7 +170,6 @@ function trackColor() { //////////////////// /** * Draw date and time - * @return {*} */ function drawDateTime() { const now = new Date; @@ -209,8 +204,9 @@ function drawDateTime() { /** * Draw track number and total count + * @param {boolean} clr - Clear area before redrawing? */ -function drawNum() { +function drawNum(clr) { let num = ""; if ("n" in info && info.n>0) { num = "#"+info.n; @@ -220,9 +216,11 @@ function drawNum() { } g.reset(); g.setFont("Vector", 30) - .setFontAlign(1, -1) // top right - .clearRect(225, 30, 120, 60) - .drawString(num, 225, 30); + .setFontAlign(1, -1); // top right + if (clr) { + g.clearRect(225, 30, 120, 60); + } + g.drawString(num, 225, 30); } /** * Clear rectangle used by track title @@ -232,8 +230,9 @@ function clearTrack() { } /** * Draw track title + * @param {boolean} clr - Clear area before redrawing? */ -function drawTrack() { +function drawTrack(clr) { let size = fitText(info.track); if (size<25) { // the title is too long: start the scroller @@ -250,7 +249,9 @@ function drawTrack() { g.setFont("Vector", size) .setFontAlign(0, 1) // center bottom .setColor(trackColor()); - clearTrack(); + if (clr) { + clearTrack(); + } g.drawString(info.track, 119, 109); } /** @@ -270,8 +271,9 @@ function drawScroller() { /** * Draw track artist and album + * @param {boolean} clr - Clear area before redrawing? */ -function drawArtistAlbum() { +function drawArtistAlbum(clr) { // we just use small enough fonts to make these always fit // calculate stuff before clear+redraw const aCol = infoColor("artist"); @@ -285,7 +287,9 @@ function drawArtistAlbum() { bSiz = 20; } g.reset(); - g.clearRect(0, 120, 240, 189); + if (clr) { + g.clearRect(0, 120, 240, 189); + } let top = 124; if (info.artist) { g.setFont("Vector", aSiz) @@ -347,7 +351,6 @@ function controlColor(ctrl) { return (ctrl in tCommand) ? "#ff0000" : "#008800"; } function drawControl(ctrl, x, y) { - if (!TCTL) {return;} g.setColor(controlColor(ctrl)); const s = 20; if (stat!==controlState) { @@ -379,10 +382,14 @@ function drawControls() { controlState = stat; } -function drawMusic() { - drawNum(); - drawTrack(); - drawArtistAlbum(); +/** + * @param {boolean} [clr=true] Clear area before redrawing? + */ +function drawMusic(clr) { + clr = !(clr===false); // undefined means yes + drawNum(clr); + drawTrack(clr); + drawArtistAlbum(clr); } //////////////////////// @@ -390,7 +397,7 @@ function drawMusic() { /////////////////////// /** * Update music info - * @param e + * @param {Object} e - Gadgetbridge musicinfo event */ function musicInfo(e) { info = e; @@ -410,7 +417,11 @@ function musicInfo(e) { } } -let tPxt, tIxt; +let tPxt, tIxt; // Timeouts to eXiT when Paused/Inactive for too long +/** + * Update music state + * @param {Object} e - Gadgetbridge musicstate event + */ function musicState(e) { stat = e.state; // if paused for five minutes, load the clock @@ -446,6 +457,7 @@ function musicState(e) { } } if (Bangle.isLCDOn()) { + drawMusic(false); // redraw in case we were fading out but resumed play drawControls(); } } @@ -473,11 +485,19 @@ function startButtonWatches() { tPress = setTimeout(() => {Bangle.showLauncher();}, 3000); } }, BTN2, {repeat: true, edge: "rising"}); - setWatch(() => { - nPress++; - clearTimeout(tPress); - tPress = setTimeout(handleButton2Press, 500); - }, BTN2, {repeat: true, edge: "falling"}); + const s = require("Storage").readJSON("gbmusic.json", 1) || {}; + if (s.simpleButton) { + setWatch(() => { + clearTimeout(tPress); + togglePlay(); + }, BTN2, {repeat: true, edge: "falling"}); + } else { + setWatch(() => { + nPress++; + clearTimeout(tPress); + tPress = setTimeout(handleButton2Press, 500); + }, BTN2, {repeat: true, edge: "falling"}); + } } function handleButton2Press() { tPress = null; @@ -500,7 +520,7 @@ function handleButton2Press() { let tCommand = {}; /** * Send command and highlight corresponding control - * @param command "play/pause/next/previous/volumeup/volumedown" + * @param {string} command - "play"/"pause"/"next"/"previous"/"volumeup"/"volumedown" */ function sendCommand(command) { Bluetooth.println(JSON.stringify({t: "music", n: command})); @@ -520,9 +540,8 @@ function togglePlay() { sendCommand(stat==="play" ? "pause" : "play"); } function startTouchWatches() { - if (!TCTL) {return;} Bangle.on("touch", side => { - if (TCTL<2 && !Bangle.isLCDOn()) {return;} + if (!Bangle.isLCDOn()) {return;} // for <2v10 firmware switch(side) { case 1: sendCommand(stat==="play" ? "pause" : "previous"); @@ -535,7 +554,7 @@ function startTouchWatches() { } }); Bangle.on("swipe", dir => { - if (TCTL<2 && !Bangle.isLCDOn()) {return;} + if (!Bangle.isLCDOn()) {return;} // for <2v10 firmware sendCommand(dir===1 ? "previous" : "next"); }); } diff --git a/apps/gbmusic/settings.js b/apps/gbmusic/settings.js index d2dafb8f3..ae013fda5 100644 --- a/apps/gbmusic/settings.js +++ b/apps/gbmusic/settings.js @@ -5,12 +5,11 @@ const SETTINGS_FILE = "gbmusic.json", storage = require("Storage"), translate = require("locale").translate; - const TOUCH_OPTIONS = ["Off", "When LCD on", "Always"]; // initialize with default settings... let s = { autoStart: true, - touch: 1, + simpleButton: false, }; // ...and overwrite them with any saved values // This way saved values are preserved if a new version adds more settings @@ -19,24 +18,27 @@ s[key] = saved[key]; } - function save(key, value) { - s[key] = value; - storage.write(SETTINGS_FILE, s); + function save(key) { + return function (value) { + s[key] = value; + storage.write(SETTINGS_FILE, s); + } } + const yesNo = (v) => translate(v ? "Yes" : "No"); let menu = { "": {"title": "Music Control"}, }; menu[translate("< Back")] = back; menu[translate("Auto start")] = { - value: s.autoStart, - format: v => translate(v ? "Yes" : "No"), - onchange: v => {save("autoStart", v);}, + value: !!s.autoStart, + format: yesNo, + onchange: save("autoStart"), }; - menu[translate("Touch")] = { - value: s.touch|0, - format: v => translate(TOUCH_OPTIONS[(v+3)%3]), - onchange: v => {save("touch", (v+3)%3);}, + menu[translate("Simple button")] = { + value: !!s.simpleButton, + format: yesNo, + onchange: save("simpleButton"), }; E.showMenu(menu); diff --git a/apps/kitchen/ChangeLog b/apps/kitchen/ChangeLog index c6ef8a39d..71548ec30 100644 --- a/apps/kitchen/ChangeLog +++ b/apps/kitchen/ChangeLog @@ -6,3 +6,5 @@ 0.06: Reduced memory footprint of compass, used direct screen access rather than arrayBuffer 0.07: Added error codes if dependancies are missing 0.08: Improved error handling for missing firmware features, added template app.kit.js +0.09: Added heart rate monitor app +0.10: Converted Stepo to use direct screen writes, added a Trip Counter feature to stepo diff --git a/apps/kitchen/README.md b/apps/kitchen/README.md index 82629835c..a829a39b0 100644 --- a/apps/kitchen/README.md +++ b/apps/kitchen/README.md @@ -1,4 +1,4 @@ -# Kitchen Combo - a multiclock format of the waypointer, walkersclock, stepo and arrow apps. +# Kitchen Combo - a multiclock format of the waypointer, walkersclock, stepo, stopwatch, heartrate and arrow apps. ![](screenshot_kitchen.jpg) @@ -50,8 +50,10 @@ The following buttons depend on which face is currently in use - Show step count in the middle of the doughnut gauge - The gauge show percentage of steps out of a goal of 10000 steps - When the battery is less than 25% the doughnut turns red +- Use BTN1 to switch to the Trip Counter, use long press to reset Trip Counter - Use BTN3 to switch to the next app + ## GPS ![](screenshot_gps.jpg) - Use BTN1 long press to switch the GPS on or off @@ -66,10 +68,16 @@ The following buttons depend on which face is currently in use - Use BTN3 to switch to the next app. ## Swatch +![](screenshot_swatch.jpg) - A simple stopwatch - BTN1 - start, stop - BTN2 - lap if the timer is running, reset if the timer is stopped +## Heart +![](screenshot_heart.jpg) +- A simple heart rate monitor, at present the app is just showing the raw value from HRM.bpm +- BTN1, long press, turn heart rate monitor on / off + ## Waypointer - Use BTN1 to select previous waypoint (when GPS is on) - Use BTN2 to select the next waypoint (when GPS is on) @@ -218,6 +226,16 @@ I have settled on directly writing to the screen using the Graphics object (g.) for the compass App. This creates a bit of flicker when the arrow moves but is more reliable than using the ArrayBuffer. +v0.09: Since adding the heart rate monitor I have noticed that I can +sometimes can a memory error when switch through the Apps back to the +Stepo App. I think this can be cured by statically allocating the +ArrayBuffer for stepo rather than using new everytime you switch back +into the stepo watch face. The problem is that the bangle memory +management / defragmentation is quite slow to run. + +v0.10: Revisited having a display buffer for the stepo part of the App. +Now use direct screen writing as it means less memory allocation and +reduces chance of getting a memory error on switching watch faces. ### Error Codes @@ -227,8 +245,12 @@ The following error codes will be displayed if one of the dependancies is not me * E-CALIB - no compass calibration data was found, see 'Compass Calibration' * E-FW - require firmware 2v08.187 or later to detect gps and compass power status -### Issues +### Issues / Future enhancements * GPS time display shows GMT and not BST, needs localising * Occassional buzzing after 2-3 days of use, seems to disappear after a reset to the launcher menu. Needs investigation +* Automatically switch the GPS power setting from Super-E to PSMOO 10 + seconds after the LCD goes off. At present I just rely on using + the GPSSetup app and set the GPS power mode that I want. +* Add a small graph to the heart rate monitor app diff --git a/apps/kitchen/compass.kit.js b/apps/kitchen/compass.kit.js index 4c85f058f..530ba021c 100644 --- a/apps/kitchen/compass.kit.js +++ b/apps/kitchen/compass.kit.js @@ -16,7 +16,7 @@ //console.log(o); } - function init(gps,sw) { + function init(gps,sw, hrm) { showMem("compass init() START"); gpsObject = gps; intervalRefSec = undefined; diff --git a/apps/kitchen/digi.kit.js b/apps/kitchen/digi.kit.js index f65880928..91ae70905 100644 --- a/apps/kitchen/digi.kit.js +++ b/apps/kitchen/digi.kit.js @@ -16,7 +16,7 @@ const Y_ACTIVITY = 116; const Y_MODELINE = 200; - function init(gps,sw) { + function init(gps,sw,hrm) { showMem("digi init 1"); days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday","Friday", "Saturday"]; prevInfo = ""; diff --git a/apps/kitchen/gps.kit.js b/apps/kitchen/gps.kit.js index 3977715f3..d6c936226 100644 --- a/apps/kitchen/gps.kit.js +++ b/apps/kitchen/gps.kit.js @@ -20,7 +20,7 @@ //console.log(o); } - function init(gps, sw) { + function init(gps, sw, hrm) { log_debug("gps init"); //log_debug(gps); gpsObject = gps; diff --git a/apps/kitchen/heart.kit.js b/apps/kitchen/heart.kit.js new file mode 100644 index 000000000..aedbadf9f --- /dev/null +++ b/apps/kitchen/heart.kit.js @@ -0,0 +1,116 @@ +(() => { + function getFace(){ + const Y_TIME = 30; + const Y_ACTIVITY = 116; + let prevTime; + let prevBpm; + let toggle = 1; + let redrawHrmPower = true; + let intervalRefSec; + let img; + let hrmObject; + + function log_debug(o) { + //console.log(o); + } + + function init(gps, sw, hrm) { + img = require("heatshrink").decompress(atob("mEwwRC/ABf/+ADBh//BQgGB//AgYDBCAQWCA4QPCDAYSC//8n4EC4AiEAAo1EBZIeDAAn8BZoKHJAYL7L64LLTa6/DAAi/CKhDjGBZBIGIwQ8IHQQ8IHQYwHBQgwFFwgwGFwgwGFwowFBQwwDFwwwEFwwwEFw4wDBRAkBERAkCERIA/AAYA=")); + prevTime = "-"; + prevBpm = "-"; + toggle = 1; + redrawHrmPower = true; + hrmObject = hrm; + intervalRefSec; + g.clear(); + } + + function freeResources() { + prevTime = undefined; + img = undefined; + } + + function startTimer() { + draw(); + intervalRefSec = setInterval(draw, 1000); + } + + function stopTimer() { + if (intervalRefSec) { intervalRefSec = clearInterval(intervalRefSec); } + } + + function onButtonShort(btn) {} + + function onButtonLong(btn) { + log_debug("toggleHRM"); + if (btn !== 1) return; + if (!Bangle.isHRMOn) return; // old firmware + hrmObject.toggleHRMPower(); + prevBpm = '-'; + toggle = 1; // ensure we draw the heart first + redrawHrmPower = true; + } + + function draw() { + let d = new Date(); + let da = d.toString().split(" "); + let time = da[4].substr(0,5); + + if (time !== prevTime) { + prevTime = time; + g.setColor(0); + g.fillRect(0, Y_TIME, 239, Y_ACTIVITY -1); + g.setColor(1,1,1); + g.setFont("Vector",80); + g.setFontAlign(0,-1); + g.drawString(time, 120, Y_TIME); + } + + let bpm = hrmObject.getBpm(); + + if (!Bangle.isHRMOn()) { + if (!redrawHrmPower) return; + redrawHrmPower = false; + g.setColor(0); + g.drawImage(img, 12, 132, {scale:2}); + g.fillRect(120,120,239,239); + g.setColor(255,0,0); + //g.setColor(0xFFC0); // yellow + g.drawImage(img, 12, 132, {scale:2}); + + g.setFont("Vector",40); + g.setFontAlign(0,0); + g.setColor(1,1,1); + g.drawString("OFF", 180, 180); + return; + } + + // draw the heart + if (++toggle % 2 === 0) { + g.setColor(0); + g.fillRect(12, 132, 108, 228); + } else { + g.setColor(255,0,0); + //g.setColor(0xFFC0); // yellow + g.drawImage(img, 12, 132, {scale:2}); + } + + // draw the bpm + if (bpm !== prevBpm) { + prevBpm = bpm; + g.setColor(0); + g.fillRect(120, 120, 239, 239); + g.setColor(1,1,1); + //g.setColor(0xFFC0); // yellow + g.setFont("Vector",52); + g.setFontAlign(0,0); + g.drawString(bpm, 180, 180); + } + } + + return {init:init, freeResources:freeResources, startTimer:startTimer, stopTimer:stopTimer, + onButtonShort:onButtonShort, onButtonLong:onButtonLong}; + } + + return getFace; +})(); diff --git a/apps/kitchen/kitchen.app.js b/apps/kitchen/kitchen.app.js index 7093950f7..c3f7bd74d 100644 --- a/apps/kitchen/kitchen.app.js +++ b/apps/kitchen/kitchen.app.js @@ -26,15 +26,17 @@ function nextFace(){ g.clear(); g.reset(); - face.init(gpsObj, swObj); + face.init(gpsObj, swObj, hrmObj, tripObject); startdraw(); } // when you feel the buzzer you know you have done a long press function longPressCheck() { Bangle.buzz(); + debug_log("long PressCheck() buzz"); if (pressTimer) { clearInterval(pressTimer); + debug_log("clear pressTimer 2"); pressTimer = undefined; } } @@ -45,6 +47,11 @@ function buttonPressed(btn) { nextFace(); } else { firstPress = getTime(); + if (pressTimer) { + debug_log("clear pressTimer 1"); + clearInterval(pressTimer); + } + debug_log("set pressTimer 1"); pressTimer = setInterval(longPressCheck, 1500); } } @@ -53,6 +60,7 @@ function buttonPressed(btn) { function buttonReleased(btn) { var dur = getTime() - firstPress; if (pressTimer) { + debug_log("clear pressTimer 3"); clearInterval(pressTimer); pressTimer = undefined; } @@ -248,6 +256,7 @@ GPS.prototype.processFix = function(fix) { this.gpsState = this.GPS_RUNNING; if (!this.last_fix.fix && !(require("Storage").readJSON("setting.json", 1) || {}).quiet) { Bangle.buzz(); // buzz on first position + debug_log("GPS fix buzz"); } this.last_fix = fix; } @@ -651,6 +660,122 @@ function stopwatchDraw() { } +/***************************************************************************** + +Heart Rate Monitor + +******************************************************************************/ + +function HRM() { + this.bpm = 0; + this.confidence = 0; +} + +HRM.prototype.log_debug = function(o) { + //console.log(o); +} + +HRM.prototype.toggleHRMPower = function() { + this.log_debug("HRM.toggleHRMPower()"); + if (!Bangle.isHRMOn) return; // old firmware + + if (!Bangle.isHRMOn()) { + this.log_debug("HRM.toggleHRMPower(powerOn)"); + Bangle.removeListener('HRM', onHRM); + Bangle.setHRMPower(1); + Bangle.on('HRM', onHRM); + } else { + this.log_debug("HRM.toggleHRMPower(powerOff)"); + Bangle.removeListener('HRM', onHRM); + Bangle.setHRMPower(0); + } + + // poke the hrt widget indicator to change + if (WIDGETS.widhrt !== undefined) { + WIDGETS.widhrt.draw(); + } +} + +HRM.prototype.getBpm = function() { + return this.bpm; +} + +HRM.prototype.getConfidence = function() { + return this.confidence; +} + +HRM.prototype.onHRM = function(hrm) { + this.bpm = hrm.bpm; + this.confidence = hrm.confidence; + this.log_debug("onHRM:(bpm)" + this.bpm); + this.log_debug("onHRM:(conf) " + this.confidence); +} + +let hrmObj = new HRM(); + +function onHRM(hrm) { + hrmObj.onHRM(hrm); +} + + +/***************************************************************************** + +Trip Counter + +******************************************************************************/ + +function TRIP() { + this.showTrip = false; + this.tripStart = 0; +} + +TRIP.prototype.resetTrip = function(steps) { + this.tripStart = (0 + steps); + console.log("resetTrip starting=" + this.tripStart); +} + +TRIP.prototype.getTrip = function(steps) { + let tripSteps = (0 + steps) - this.tripStart; + console.log("getTrip steps=" + steps); + console.log("getTrip tripStart=" + this.tripStart); + console.log("getTrip=" + tripSteps); + return tripSteps; +} + +TRIP.prototype.getTripState = function() { + return this.showTrip; +} + +TRIP.prototype.setTripState = function(t) { + this.showTrip = t; +} + +let tripObject = new TRIP(); + +/***************************************************************************** + +Debug Object + +******************************************************************************/ + +/* +function DEBUG() { + this.logfile = require("Storage").open("debug.log","a"); +} + +DEBUG.prototype.log = function(msg) { + let timestamp = new Date().toString().split(" ")[4]; + let line = timestamp + ", " + msg + "\n"; + this.logfile.write(line); +} + +debugObj = new DEBUG(); +*/ + +function debug_log(m) { + //debugObj.log(m); +} + /***************************************************************************** Start App @@ -659,6 +784,6 @@ Start App g.clear(); Bangle.loadWidgets(); -face.init(gpsObj,swObj); +face.init(gpsObj,swObj, hrmObj, tripObject); startdraw(); setButtons(); diff --git a/apps/kitchen/screenshot_heart.jpg b/apps/kitchen/screenshot_heart.jpg new file mode 100644 index 000000000..f0951a9b0 Binary files /dev/null and b/apps/kitchen/screenshot_heart.jpg differ diff --git a/apps/kitchen/screenshot_swatch.jpg b/apps/kitchen/screenshot_swatch.jpg new file mode 100644 index 000000000..e8518d586 Binary files /dev/null and b/apps/kitchen/screenshot_swatch.jpg differ diff --git a/apps/kitchen/stepo.kit.js b/apps/kitchen/stepo.kit.js index 072cb43f1..9fa34e8ab 100644 --- a/apps/kitchen/stepo.kit.js +++ b/apps/kitchen/stepo.kit.js @@ -1,44 +1,28 @@ (() => { function getFace(){ - var pal4color; - var pal4red; - var buf; var intervalRefSec; + var trip; + var prevSteps; - function init(g,sw) { - showMem("stepo init 1"); - pal4color = new Uint16Array([0x0000,0xFFFF,0x7BEF,0xAFE5],0,2); // b,w,grey,greenyellow - pal4red = new Uint16Array([0x0000,0xFFFF,0xF800,0xAFE5],0,2); // b,w,red,greenyellow - buf = Graphics.createArrayBuffer(120,120,2,{msb:true}); - showMem("stepo init 2"); + function init(g,sw,hrm,tr) { + trip = tr; } function freeResources() { - showMem("stepo free 1"); - pal4color = undefined; - pal4red = undefined; - buf = undefined; - showMem("stepo free 2"); - } - - function showMem(msg) { - var val = process.memory(); - var str = msg + " " + Math.round(val.usage*100/val.total) + "%"; - //console.log(str); + trip = undefined; + prevSteps = -1; } - function flip(x,y) { - g.drawImage({width:120,height:120,bpp:2,buffer:buf.buffer, palette:pal4color}, x, y); - buf.clear(); + function onButtonShort(btn) { + trip.setTripState(!trip.getTripState()); + drawStepText(); } - function flip_red(x,y) { - g.drawImage({width:120,height:120,bpp:2,buffer:buf.buffer, palette:pal4red}, x, y); - buf.clear(); + function onButtonLong(btn) { + trip.resetTrip(getSteps()); + trip.setTripState(true); + drawStepText(); } - - function onButtonShort(btn) {} - function onButtonLong(btn) {} function radians(a) { return a*Math.PI/180; @@ -55,10 +39,16 @@ function drawSteps() { var i = 0; - var cx = 60; - var cy = 60; + var cx = 60 + 60; + var cy = 60 + 115; var r = 56; var steps = getSteps(); + + if (prevSteps == steps) + return; + + prevSteps = steps; + var percent = steps / 10000; if (percent > 1) percent = 1; @@ -66,38 +56,60 @@ var startrot = 0 - 180; var midrot = -180 - (360 * percent); var endrot = -360 - 180; - - buf.setColor(3); // green-yellow + + g.setColor(0xAFE5); // greenyellow // draw guauge for (i = startrot; i > midrot; i -= 4) { x = cx + r * Math.sin(radians(i)); y = cy + r * Math.cos(radians(i)); - buf.fillCircle(x,y,4); + g.fillCircle(x,y,4); } - buf.setColor(2); // grey - - // draw remainder of guage in grey - for (i = midrot; i > endrot; i -= 4) { - x = cx + r * Math.sin(radians(i)); - y = cy + r * Math.cos(radians(i)); - buf.fillCircle(x,y,4); - } - - // draw steps - buf.setColor(1); // white - buf.setFont("Vector", 24); - buf.setFontAlign(0,0); - buf.drawString(steps, cx, cy); - // change the remaining color to RED if battery is below 25% if (E.getBattery() > 25) - flip(60,115); + g.setColor(0x7BEF); // grey else - flip_red(60,115); + g.setColor(0xF800); // red + + // draw remainder of guage in grey or red + for (i = midrot; i > endrot; i -= 4) { + x = cx + r * Math.sin(radians(i)); + y = cy + r * Math.cos(radians(i)); + g.fillCircle(x,y,4); + } } + function drawStepText() { + var cx = 60 + 60; + var cy = 60 + 115; + var r = 56; + var steps = getSteps(); + + /* + * if our trip count is greater than todays steps then we have + * rolled over to the next day so we should reset the trip counter + */ + if (trip.getTrip(steps) < 0) + trip.resetTrip(steps); + + // show trip count or total steps today + g.setFontAlign(0,0); + g.setFont("Vector", 24); + + // clear the space for the text + g.clearRect(cx - (r - 12), cy - 16, cx + (r - 12), cy + 16); + + if (trip.getTripState() == true) { + g.setColor(0x7BEF); // grey + //g.setColor(1,0,0); // red + g.drawString(trip.getTrip(steps), cx, cy); + } else { + g.setColor(1,1,1); // white + g.drawString(steps, cx, cy); + } + } + function draw() { var d = new Date(); var da = d.toString().split(" "); @@ -110,6 +122,7 @@ g.drawString(time, 120, 30, true); drawSteps(); + drawStepText(); } function getSteps() { @@ -132,5 +145,4 @@ } return getFace; - })(); diff --git a/apps/kitchen/swatch.kit.js b/apps/kitchen/swatch.kit.js index efec39d97..b88518cbd 100644 --- a/apps/kitchen/swatch.kit.js +++ b/apps/kitchen/swatch.kit.js @@ -2,7 +2,7 @@ function getFace(){ let swObject = undefined; - function init(gps, sw) { + function init(gps, sw, hrm) { swObject = sw; g.clear(); } diff --git a/apps/sweepclock/ChangeLog b/apps/sweepclock/ChangeLog index d5cf3753c..8eeb95c09 100644 --- a/apps/sweepclock/ChangeLog +++ b/apps/sweepclock/ChangeLog @@ -1,2 +1,3 @@ 0.01: Initial Release 0.02: Added Colour Themes +0.03: Added Date diff --git a/apps/sweepclock/README.md b/apps/sweepclock/README.md index 8ddb7decb..cbdb2a3f8 100644 --- a/apps/sweepclock/README.md +++ b/apps/sweepclock/README.md @@ -23,7 +23,12 @@ Button 3 (bottom right button) is used to change the colour | ---- | ---- | ---- | | ![](./color-01.jpg) | ![](color-02.jpg) | ![](color-03.jpg) | +### Button 4 +Button 4 (bottom left of screen) is used to change the date positioning (or to remove from the screen) +| Top Right | Bottom Right | Bottom Left | Top Left | +| ---- | ---- | ---- | ---- | +| ![](./date-01.jpg) | ![](date-02.jpg) | ![](date-03.jpg) | ![](date-04.jpg) | ## Further Details @@ -35,4 +40,4 @@ Reach out to adrian@adriankirk.com if you have feature requests or notice bugs. ## Creator -Made by [Adrian Kirk](mailto:adrian@adriankirk.com) +Made by [Adrian Kirk](mailto:adrian@adriankirk.com) \ No newline at end of file diff --git a/apps/sweepclock/date-01.jpg b/apps/sweepclock/date-01.jpg new file mode 100644 index 000000000..79d12e75b Binary files /dev/null and b/apps/sweepclock/date-01.jpg differ diff --git a/apps/sweepclock/date-02.jpg b/apps/sweepclock/date-02.jpg new file mode 100644 index 000000000..14a64980c Binary files /dev/null and b/apps/sweepclock/date-02.jpg differ diff --git a/apps/sweepclock/date-03.jpg b/apps/sweepclock/date-03.jpg new file mode 100644 index 000000000..e30a01932 Binary files /dev/null and b/apps/sweepclock/date-03.jpg differ diff --git a/apps/sweepclock/date-04.jpg b/apps/sweepclock/date-04.jpg new file mode 100644 index 000000000..6e65a148f Binary files /dev/null and b/apps/sweepclock/date-04.jpg differ diff --git a/apps/sweepclock/sweepclock.js b/apps/sweepclock/sweepclock.js index 9c53efa55..df6b09e3d 100644 --- a/apps/sweepclock/sweepclock.js +++ b/apps/sweepclock/sweepclock.js @@ -6,6 +6,7 @@ const screen_center_x = g.getWidth()/2; const screen_center_y = 10 + g.getHeight()/2; +const TWO_PI = 2*Math.PI; require("FontCopasetic40x58Numeric").add(Graphics); @@ -101,14 +102,14 @@ class ThinHand extends Hand { // and then call the predicate to see if a redraw is needed this.draw_test(this.angle,this.last_draw_time) ){ // rub out the old hand line - background = color_schemes[color_scheme_index].background; + var background = color_schemes[color_scheme_index].background; g.setColor(background[0],background[1],background[2]); g.drawLine(this.centerX, this.centerY, this.last_x, this.last_y); // Now draw the new hand line - hand_color = color_schemes[color_scheme_index][this.color_theme]; + var hand_color = color_schemes[color_scheme_index][this.color_theme]; g.setColor(hand_color[0],hand_color[1],hand_color[2]); - x2 = this.centerX + this.length*Math.sin(angle); - y2 = this.centerY - this.length*Math.cos(angle); + var x2 = this.centerX + this.length*Math.sin(angle); + var y2 = this.centerY - this.length*Math.cos(angle); g.drawLine(this.centerX, this.centerY, x2, y2); // and store the last draw details for the next call this.last_x = x2; @@ -170,7 +171,7 @@ class ThickHand extends Hand { // method to move the hand to a new angle moveTo(angle){ if(Math.abs(angle - this.angle) > this.tolerance || this.draw_test(this.angle - this.delta_base,this.angle + this.delta_base ,this.last_draw_time) ){ - background = color_schemes[color_scheme_index].background; + var background = color_schemes[color_scheme_index].background; g.setColor(background[0],background[1],background[2]); g.fillPoly([this.last_x1, this.last_y1, @@ -182,20 +183,20 @@ class ThickHand extends Hand { this.last_y4 ]); // bottom left - x1 = this.centerX + + var x1 = this.centerX + this.vertex_radius_base*Math.sin(angle - this.delta_base); - y1 = this.centerY - this.vertex_radius_base*Math.cos(angle - this.delta_base); + var y1 = this.centerY - this.vertex_radius_base*Math.cos(angle - this.delta_base); // bottom right - x2 = this.centerX + + var x2 = this.centerX + this.vertex_radius_base*Math.sin(angle + this.delta_base); - y2 = this.centerY - this.vertex_radius_base*Math.cos(angle + this.delta_base); + var y2 = this.centerY - this.vertex_radius_base*Math.cos(angle + this.delta_base); // top right - x3 = this.centerX + this.vertex_radius_top*Math.sin(angle + this.delta_top); - y3 = this.centerY - this.vertex_radius_top*Math.cos(angle + this.delta_top); + var x3 = this.centerX + this.vertex_radius_top*Math.sin(angle + this.delta_top); + var y3 = this.centerY - this.vertex_radius_top*Math.cos(angle + this.delta_top); // top left - x4 = this.centerX + this.vertex_radius_top*Math.sin(angle - this.delta_top); - y4 = this.centerY - this.vertex_radius_top*Math.cos(angle - this.delta_top); - hand_color = color_schemes[color_scheme_index][this.color_theme]; + var x4 = this.centerX + this.vertex_radius_top*Math.sin(angle - this.delta_top); + var y4 = this.centerY - this.vertex_radius_top*Math.cos(angle - this.delta_top); + var hand_color = color_schemes[color_scheme_index][this.color_theme]; g.setColor(hand_color[0],hand_color[1],hand_color[2]); g.fillPoly([x1,y1, x2,y2, @@ -222,25 +223,27 @@ class ThickHand extends Hand { let force_redraw = false; // The seconds hand is the main focus and is set to redraw on every cycle let seconds_hand = new ThinHand(screen_center_x, - screen_center_y, - 95, - 0, - (angle, last_draw_time) => false, - "second_hand"); + screen_center_y, + 95, + 0, + (angle, last_draw_time) => false, + "second_hand"); + // The minute hand is set to redraw at a 250th of a circle, // when the second hand is ontop or slighly overtaking // or when a force_redraw is called let minutes_hand_redraw = function(angle, last_draw_time){ return force_redraw || (seconds_hand.angle > angle && - Math.abs(seconds_hand.angle - angle) <2*Math.PI/25 && + Math.abs(seconds_hand.angle - angle) 500); }; -let minutes_hand = new ThinHand(screen_center_x, - screen_center_y, - 80, - 2*Math.PI/250, - minutes_hand_redraw, - "minute_hand"); +let minutes_hand = new ThinHand(screen_center_x, + screen_center_y, + 80, + TWO_PI/250, + minutes_hand_redraw, + "minute_hand" +); // The hour hand is a thick hand so we have to redraw when the minute hand // overlaps from its behind andle coverage to its ahead angle coverage. let hour_hand_redraw = function(angle_from, angle_to, last_draw_time){ @@ -249,48 +252,107 @@ let hour_hand_redraw = function(angle_from, angle_to, last_draw_time){ new Date().getTime() - last_draw_time.getTime() > 500); }; let hours_hand = new ThickHand(screen_center_x, - screen_center_y, - 40, - 2*Math.PI/600, - hour_hand_redraw, - "hour_hand", - 5, - 4); + screen_center_y, + 40, + TWO_PI/600, + hour_hand_redraw, + "hour_hand", + 5, + 4); function draw_clock(){ - date = new Date(); + var date = new Date(); draw_background(); draw_hour_digit(date); draw_seconds(date); draw_mins(date); draw_hours(date); + draw_date(date); force_redraw = false; } + +var local = require('locale'); +var last_date = null; +var last_datestr = null; +var last_coords = null; +var date_coords = [ + { name: "topright", coords:[180,30]}, + { name: "bottomright", coords:[180,220]}, + { name: "bottomleft", coords: [5,220]}, + { name: "topleft", coords:[5,30]}, + { name: "offscreen", coords: [240,30]} +]; +var date_coord_index = 0; + +function draw_date(date){ + if(force_redraw || last_date == null || last_date.getDate() != date.getDate()){ + //console.log("redrawing date"); + g.setFontAlign(-1,-1,0); + g.setFont("Vector",15); + if(last_coords != null && last_datestr != null) { + var background = color_schemes[color_scheme_index].background; + g.setColor(background[0], background[1], background[2]); + g.drawString(last_datestr, last_coords[0], last_coords[1]); + } + var coords = date_coords[date_coord_index].coords; + if(coords != null) { + var date_format = local.dow(date,1) + " " + date.getDate(); + var numeral_color = color_schemes[color_scheme_index].numeral; + g.setColor(numeral_color[0], numeral_color[1], numeral_color[2]); + g.drawString(date_format, coords[0], coords[1]); + last_date = date; + last_datestr = date_format; + last_coords = coords; + } + } +} + +function next_datecoords() { + date_coord_index = date_coord_index + 1; + if (date_coord_index >= date_coords.length) { + date_coord_index = 0; + } + //console.log("date coord index->" + date_coord_index); + force_redraw = true; +} + +function set_datecoords(date_name){ + console.log("setting date:" + date_name); + for (var i=0; i < date_coords.length; i++) { + if(date_coords[i].getName() == date_name){ + date_coord_index = i; + force_redraw = true; + console.log("date match"); + break; + } + } +} + // drawing the second the millisecond as we need the fine gradation // for the sweep second hand. function draw_seconds(date){ - seconds = date.getSeconds() + date.getMilliseconds()/1000; - seconds_frac = seconds / 60; - seconds_angle = 2*Math.PI*seconds_frac; + var seconds = date.getSeconds() + date.getMilliseconds()/1000; + var seconds_frac = seconds / 60; + var seconds_angle = TWO_PI*seconds_frac; seconds_hand.moveTo(seconds_angle); } // drawing the minute includes the second and millisec to make the // movement as continuous as possible. function draw_mins(date,seconds_angle){ - mins = date.getMinutes() + date.getSeconds()/60 + date.getMilliseconds()/(60*1000); - mins_frac = mins / 60; - mins_angle = 2*Math.PI*mins_frac; - redraw = minutes_hand.moveTo(mins_angle); + var mins = date.getMinutes() + date.getSeconds()/60 + date.getMilliseconds()/(60*1000); + var mins_frac = mins / 60; + var mins_angle = TWO_PI*mins_frac; + var redraw = minutes_hand.moveTo(mins_angle); if(redraw){ //console.log("redraw mins"); } } function draw_hours(date){ - hours = (date.getHours() % 12) + date.getMinutes()/60 + date.getSeconds()/3600; - hours_frac = hours / 12; - hours_angle = 2*Math.PI*hours_frac; - redraw = hours_hand.moveTo(hours_angle); + var hours = (date.getHours() % 12) + date.getMinutes()/60 + date.getSeconds()/3600; + var hours_frac = hours / 12; + var hours_angle = TWO_PI*hours_frac; + var redraw = hours_hand.moveTo(hours_angle); if(redraw){ //console.log("redraw hours"); } @@ -363,6 +425,7 @@ class CopasetFont extends NumeralFont{ x,y+dim[1] ]); g.setColor(1.0,1.0,1.0);*/ + g.setFontAlign(-1,-1,0); g.setFontCopasetic40x58Numeric(); g.drawString(hour_txt,x,y); } @@ -408,6 +471,7 @@ class RomanNumeralFont extends NumeralFont{ getDimensions(hour){ return this.dimension_map[hour];} hour_txt(hour){ return this.txt_map[hour]; } draw(hour_txt,x,y){ + g.setFontAlign(-1,-1,0); g.setFont("Vector",40); g.drawString(hour_txt,x,y); } @@ -426,7 +490,7 @@ function reifyasin(x,y,asin_angle){ } else if(x < 0 && y < 0){ return Math.PI - asin_angle; } else { - return 2*Math.PI + asin_angle; + return TWO_PI + asin_angle; } } @@ -434,7 +498,7 @@ function reifyasin(x,y,asin_angle){ // rather than 0 to 2PI function rebaseNegative(angle){ if(angle > Math.PI){ - return angle - 2*Math.PI; + return angle - TWO_PI; } else { return angle; } @@ -444,7 +508,7 @@ function rebaseNegative(angle){ // rather than -pi to pi function rebasePositive(angle){ if(angle < 0){ - return angle + 2*Math.PI; + return angle + TWO_PI; } else { return angle; } @@ -471,48 +535,48 @@ class HourScriber { this.numeral_font = numeral_font; } drawHour(hours){ - changed = false; + var changed = false; if(this.curr_hours != hours || this.curr_numeral_font !=this.numeral_font){ - background = color_schemes[color_scheme_index].background; + var background = color_schemes[color_scheme_index].background; g.setColor(background[0],background[1],background[2]); this.curr_numeral_font.draw(this.curr_hour_str, this.curr_hour_x, this.curr_hour_y); //console.log("erasing old hour"); - hours_frac = hours / 12; - angle = 2*Math.PI*hours_frac; - dimensions = this.numeral_font.getDimensions(hours); + var hours_frac = hours / 12; + var angle = TWO_PI*hours_frac; + var dimensions = this.numeral_font.getDimensions(hours); // we set the radial coord to be in the middle // of the drawn text. - width = dimensions[0]; - height = dimensions[1]; - delta_center_x = this.radius*Math.sin(angle) - width/2; - delta_center_y = this.radius*Math.cos(angle) + height/2; + var width = dimensions[0]; + var height = dimensions[1]; + var delta_center_x = this.radius*Math.sin(angle) - width/2; + var delta_center_y = this.radius*Math.cos(angle) + height/2; this.curr_hour_x = screen_center_x + delta_center_x; this.curr_hour_y = screen_center_y - delta_center_y; this.curr_hour_str = this.numeral_font.hour_txt(hours); // now work out the angle of the beginning and the end of the // text box so we know when to redraw // bottom left angle - x1 = delta_center_x; - y1 = delta_center_y; - r1 = Math.sqrt(x1*x1 + y1*y1); - angle1 = reifyasin(x1,y1,Math.asin(x1/r1)); + var x1 = delta_center_x; + var y1 = delta_center_y; + var r1 = Math.sqrt(x1*x1 + y1*y1); + var angle1 = reifyasin(x1,y1,Math.asin(x1/r1)); // bottom right angle - x2 = delta_center_x; - y2 = delta_center_y - height; - r2 = Math.sqrt(x2*x2 + y2*y2); - angle2 = reifyasin(x2,y2,Math.asin(x2/r2)); + var x2 = delta_center_x; + var y2 = delta_center_y - height; + var r2 = Math.sqrt(x2*x2 + y2*y2); + var angle2 = reifyasin(x2,y2,Math.asin(x2/r2)); // top left angle - x3 = delta_center_x + width; - y3 = delta_center_y; - r3 = Math.sqrt(x3*x3 + y3*y3); - angle3 = reifyasin(x3,y3, Math.asin(x3/r3)); + var x3 = delta_center_x + width; + var y3 = delta_center_y; + var r3 = Math.sqrt(x3*x3 + y3*y3); + var angle3 = reifyasin(x3,y3, Math.asin(x3/r3)); // top right angle - x4 = delta_center_x + width; - y4 = delta_center_y - height; - r4 = Math.sqrt(x4*x4 + y4*y4); - angle4 = reifyasin(x4,y4,Math.asin(x4/r4)); + var x4 = delta_center_x + width; + var y4 = delta_center_y - height; + var r4 = Math.sqrt(x4*x4 + y4*y4); + var angle4 = reifyasin(x4,y4,Math.asin(x4/r4)); if(Math.min(angle1,angle2,angle3,angle4) < Math.PI && Math.max(angle1,angle2,angle3,angle4) > 1.5*Math.PI){ angle1 = rebaseNegative(angle1); angle2 = rebaseNegative(angle2); @@ -532,7 +596,7 @@ class HourScriber { } if(changed || this.draw_test(this.angle_from, this.angle_to, this.last_draw_time) ){ - numeral_color = color_schemes[color_scheme_index].numeral; + var numeral_color = color_schemes[color_scheme_index].numeral; g.setColor(numeral_color[0],numeral_color[1],numeral_color[2]); this.numeral_font.draw(this.curr_hour_str,this.curr_hour_x,this.curr_hour_y); this.last_draw_time = new Date(); @@ -547,18 +611,18 @@ let numeral_fonts_index = 0; * predicate for deciding when the digit has to be redrawn */ let hour_numeral_redraw = function(angle_from, angle_to, last_draw_time){ - seconds_hand_angle = seconds_hand.angle; + var seconds_hand_angle = seconds_hand.angle; // we have to cope with the 12 problem where the // left side of the box has a value almost 2PI and the right // side has a small positive value. The values are rebased so // that they can be compared if(angle_from > angle_to && angle_from > 1.5*Math.PI){ - angle_from = angle_from - 2*Math.PI; + angle_from = angle_from - TWO_PI; if(seconds_hand_angle > Math.PI) - seconds_hand_angle = seconds_hand_angle - 2*Math.PI; + seconds_hand_angle = seconds_hand_angle - TWO_PI; } //console.log("initial:" + angle_from + "/" + angle_to + " seconds " + seconds_hand_angle); - redraw = force_redraw || + var redraw = force_redraw || (seconds_hand_angle >= angle_from && seconds_hand_angle <= angle_to) || (minutes_hand.last_draw_time.getTime() > last_draw_time.getTime()); if(redraw){ @@ -585,8 +649,8 @@ function next_font(){ } function draw_hour_digit(date){ - hours = date.getHours() % 12; - mins = date.getMinutes(); + var hours = date.getHours() % 12; + var mins = date.getMinutes(); if(mins > 30){ hours = (hours +1) % 12; } @@ -598,7 +662,7 @@ function draw_hour_digit(date){ function draw_background(){ if(force_redraw){ - background = color_schemes[color_scheme_index].background; + var background = color_schemes[color_scheme_index].background; g.setColor(background[0],background[1],background[2]); g.fillPoly([0,25, 0,240, @@ -625,7 +689,7 @@ function set_colorscheme(colorscheme_name){ if(color_schemes[i].name == colorscheme_name){ color_scheme_index = i; force_redraw = true; - console.log("match"); + console.log("color scheme match"); break; } } @@ -641,7 +705,7 @@ function set_font(font_name){ if(numeral_fonts[i].getName() == font_name){ numeral_fonts_index = i; force_redraw = true; - console.log("match"); + console.log("font match"); hour_scriber.setNumeralFont(numeral_fonts[numeral_fonts_index]); break; } @@ -653,7 +717,7 @@ function set_font(font_name){ */ function load_settings(){ try{ - settings = require("Storage").readJSON("sweepclock.settings.json"); + var settings = require("Storage").readJSON("sweepclock.settings.json"); if(settings != null){ console.log("loaded:" + JSON.stringify(settings)); if(settings.color_scheme != null){ @@ -662,6 +726,9 @@ function load_settings(){ if(settings.font != null){ set_font(settings.font); } + if(settings.date != null){ + set_datecoords(settings.date); + } } else { console.log("no settings to load"); } @@ -674,9 +741,10 @@ function load_settings(){ * Called on button press to save down the last preference settings */ function save_settings(){ - settings = { + var settings = { font : numeral_fonts[numeral_fonts_index].getName(), color_scheme : color_schemes[color_scheme_index].name, + date: date_coords[date_coord_index].name }; console.log("saving:" + JSON.stringify(settings)); require("Storage").writeJSON("sweepclock.settings.json",settings); @@ -753,9 +821,17 @@ function button3pressed(){ save_settings(); } +function button4pressed(){ + //console.log("button 4 pressed"); + next_datecoords(); + save_settings(); +} + // Handle button 1 being pressed setWatch(button1pressed, BTN1,{repeat:true,edge:"falling"}); // Handle button 3 being pressed setWatch(button3pressed, BTN3,{repeat:true,edge:"falling"}); +// Handle button 3 being pressed +setWatch(button4pressed, BTN4,{repeat:true,edge:"falling"}); diff --git a/core b/core index 1b1293a5e..7d04c4884 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 1b1293a5eb9b8bb9e4f743c4599f0587f597d368 +Subproject commit 7d04c488496c873f392c5a068f72a6c75df40f70