diff --git a/apps/regattatimer/ChnageLog b/apps/regattatimer/ChnageLog index 0789c830e..81eece2d3 100644 --- a/apps/regattatimer/ChnageLog +++ b/apps/regattatimer/ChnageLog @@ -1,2 +1,3 @@ -0.01: (2023-02-23) initial alpha upload -0.02: (2023-02-23) fixing minor issues with settings +0.01: (2024-02-23) initial alpha upload +0.02: (2024-02-23) fixed minor issues with settings +0.03: (2024-03-01) advanced settings, rearanged ui elements, fixed rendering problems diff --git a/apps/regattatimer/README.md b/apps/regattatimer/README.md index 180c8cb5d..dbf924775 100644 --- a/apps/regattatimer/README.md +++ b/apps/regattatimer/README.md @@ -3,7 +3,7 @@ ## Modes * **Idle** - On startup the application is in idle mode showing a large 5 in the centre of the screen. + On startup the application is in idle mode showing a large 5 in the centre of the screen and the time of day below. `Button` switches to start mode. * **Start** During the countdown, the screen changes the layout several times to use as much space as @@ -11,29 +11,55 @@ When time is up the buzzer sounds and the application switches to race mode. `Button` switches to idle mode. * **Race** - Race time, local time, SOA and number of GPS satellites available are displayed. + Race time, local time, SOA, number reachable GPS satellites and battery level are shown. `Button` switches to "stopped mode". * **Stoped** + The race counter stops. `Button` switches to idle mode. ## Screenshots -![Start mode minutes and seconds](screenshot-1.png) -![Start mode seconds](screenshot-2.png) +*Idle mode: showing a big 5 and time of day below* +![Idle mode: showing a big 5 and time of day below](screenshot-1.png) + +*Start mode: minutes and seconds* +![Start mode: minutes and seconds](screenshot-2.png) + +*Start mode: seconds* +![Start mode: seconds](screenshot-3.png) + +*Race mode: elapsed time, time of day, speed, satellites, battery* +![Race mode: elapsed time, time of day, speed, satellites, battery](screenshot-4.png) + +*Race mode: with german abbreviations* +![Race mode: with german abbreviations](screenshot-5.png) + +*Settings page: main* +![Settings page: main](screenshot-6.png) + +*Settings page: choose the theme* +![Settings page: choose the theme](screenshot-7.png) ## Localization Localization is done by the Bangle.js 2 app "Languages" -* Go to: https://banglejs.com/apps/ -* Search for app: Languages +* Go to [banglejs.com/apps](https://banglejs.com/apps/) +* Search for app "Languages" * Click the "arrow up" or "burger" icon * Choose your language from the dropdown * Click `upload` +**Some nautical abbreviations which are not part of the banglejs2 Languages packages are stored in `translations.json`.** + ## Feedback -Report bugs, request a feature at https://www.github.com/naden +Report bugs or request a feature at [github.com/naden](https://github.com/naden) + +## Roadmap +* adding a seconds coundown layout to mimic a classic regatta chronograph ## Created by -© 2021 - 2023 https://naden.de +© 2021 - 2024 [naden.de](https://naden.de) + +Icons by [Icons8](https://icons8.com/) diff --git a/apps/regattatimer/app-icon.js b/apps/regattatimer/app-icon.js index aa8982414..8f9c37a94 100644 --- a/apps/regattatimer/app-icon.js +++ b/apps/regattatimer/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwxH+AH4A/ACaaCBRAIQ/2sF6IKSBBGsAAJfRBKQHGxAvCMKohEBBgACwQuDSLJfPwIuESCJAQAAouGMCQuVdgYvowIuJGEYuCF9YuNF53OAAS6PAAQvKGBguDGBouQF7iLDF9QuTGBgvNFwwvad5XB4OkCYwuOF5gAIFwPB4QvqFwRfYGBQmDAA6/CFyovVd4YvqBoYvXGBIqE3QOIGAgvbGAm6Lggvp3e7MBYuSF5RgRF6aQYGAQveeQoAEF7AtKF6GBFbYwTFbgAGsYAZF9xfvF/4wJrtdEIoHMFKNeAAQvDA4YmDA5ofHFpWCwQSDA7wvHBgOI1utxAFBA74vHBgIAlF/4v/F64A/AH4A7A")) +require("heatshrink").decompress(atob("mEw4n/8H/BAWlsEI0ExkFj0H34GcgHnwGUsHO4H/kEhkGl4He8HeI8dgCyvTiM0ruABxNoxAACwwIC4MRAAMUkAWHgoNCAAMdBIVBBAccuAXGsIXIwtEmIxD0AXFhgXIAAMI6oZCnIXFh1VqtRC44AB2RkCqBiHC5UAhIxBip5KC5EA8gwIyMRiYXKgyWBjIIEhQgBpIXKgEEEwKSEA4MU3IXLhYwBoAHDuMRn8JC5cA8cRi4eDTIOQC5oNBjgFChoFChEx4wXKgApB6BeDiQEBxVgC5chMAeBiM7CZYAD2cRjAEB6L3JAA7oBNwVRJgYANOQMVAgKtBwAXPhDRBAgMxiYDBylEB4lk+C3D6gnBCYYbDrAnFrngIgeUDoKoBgEGC4dHyxWEqgXDXAIXBLYNgC4ldykAhWoIwNk8EL1TIBC4pHEBYOAgV+gFV6mbg13C4hHCMYcGqEMd4fXuhOEC4R3DU4eUpLPFL4kFwCnEa6/RiNQC58FiMdAgOBiM7C5+ziMYMwURiQXPkMRoAEBgURjgXPUwJyDAoOQCxsJFIOwAwVxiM+C5vjiMXY4itBaoYAIgzRBLwQABhUxA4oAHE4MT0AIEyIwMFwRGEYwcRpwXJ8gNBdA9RHIKSIhJVBir3JTIMrBQuyWoIuIAAOTBgMTruAA4MI6otBiM3KZMKNYIZC4lMCoSDBRgoAFg4+CAAscuDjMhoxDFofQfZpaCoYVBmhkDACEGbpQAY")) diff --git a/apps/regattatimer/app.js b/apps/regattatimer/app.js index f687353c8..87769ee0e 100644 --- a/apps/regattatimer/app.js +++ b/apps/regattatimer/app.js @@ -1,9 +1,9 @@ /** * Regatta Timer - * speed of advance */ const Layout = require("Layout"); -const locale = require("locale").name.substring(0, 2); +const locale = require("locale").name == "system" ? "en" : require("locale").name.substring(0, 2); +const hs = require("heatshrink"); // "Anton" bold font Graphics.prototype.setFontAnton = function(scale) { @@ -11,84 +11,156 @@ Graphics.prototype.setFontAnton = function(scale) { g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAAA/gAAAAAAAAAAP/gAAAAAAAAAH//gAAAAAAAAB///gAAAAAAAAf///gAAAAAAAP////gAAAAAAD/////gAAAAAA//////gAAAAAP//////gAAAAH///////gAAAB////////gAAAf////////gAAP/////////gAD//////////AA//////////gAA/////////4AAA////////+AAAA////////gAAAA///////wAAAAA//////8AAAAAA//////AAAAAAA/////gAAAAAAA////4AAAAAAAA///+AAAAAAAAA///gAAAAAAAAA//wAAAAAAAAAA/8AAAAAAAAAAA/AAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////AAAAAB///////8AAAAH////////AAAAf////////wAAA/////////4AAB/////////8AAD/////////+AAH//////////AAP//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wA//8AAAAAB//4A//wAAAAAAf/4A//gAAAAAAP/4A//gAAAAAAP/4A//gAAAAAAP/4A//wAAAAAAf/4A///////////4Af//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH//////////AAD/////////+AAB/////////8AAA/////////4AAAP////////gAAAD///////+AAAAAf//////4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gAAAAAAAAAAP/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/AAAAAAAAAAA//AAAAAAAAAAA/+AAAAAAAAAAB/8AAAAAAAAAAD//////////gAH//////////gAP//////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/4AAAAB/gAAD//4AAAAf/gAAP//4AAAB//gAA///4AAAH//gAB///4AAAf//gAD///4AAA///gAH///4AAD///gAP///4AAH///gAP///4AAP///gAf///4AAf///gAf///4AB////gAf///4AD////gA////4AH////gA////4Af////gA////4A/////gA//wAAB/////gA//gAAH/////gA//gAAP/////gA//gAA///8//gA//gAD///w//gA//wA////g//gA////////A//gA///////8A//gA///////4A//gAf//////wA//gAf//////gA//gAf/////+AA//gAP/////8AA//gAP/////4AA//gAH/////gAA//gAD/////AAA//gAB////8AAA//gAA////wAAA//gAAP///AAAA//gAAD//8AAAA//gAAAP+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/+AAAAAD/wAAB//8AAAAP/wAAB///AAAA//wAAB///wAAB//wAAB///4AAD//wAAB///8AAH//wAAB///+AAP//wAAB///+AAP//wAAB////AAf//wAAB////AAf//wAAB////gAf//wAAB////gA///wAAB////gA///wAAB////gA///w//AAf//wA//4A//AAA//wA//gA//AAAf/wA//gB//gAAf/wA//gB//gAAf/wA//gD//wAA//wA//wH//8AB//wA///////////gA///////////gA///////////gA///////////gAf//////////AAf//////////AAP//////////AAP/////////+AAH/////////8AAH///+/////4AAD///+f////wAAA///8P////gAAAf//4H///+AAAAH//gB///wAAAAAP4AAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAAAAAA//wAAAAAAAAAP//wAAAAAAAAB///wAAAAAAAAf///wAAAAAAAH////wAAAAAAA/////wAAAAAAP/////wAAAAAB//////wAAAAAf//////wAAAAH///////wAAAA////////wAAAP////////wAAA///////H/wAAA//////wH/wAAA/////8AH/wAAA/////AAH/wAAA////gAAH/wAAA///4AAAH/wAAA//+AAAAH/wAAA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAH/4AAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//8AAA/////+B///AAA/////+B///wAA/////+B///4AA/////+B///8AA/////+B///8AA/////+B///+AA/////+B////AA/////+B////AA/////+B////AA/////+B////gA/////+B////gA/////+B////gA/////+A////gA//gP/gAAB//wA//gf/AAAA//wA//gf/AAAAf/wA//g//AAAAf/wA//g//AAAA//wA//g//gAAA//wA//g//+AAP//wA//g////////gA//g////////gA//g////////gA//g////////gA//g////////AA//gf///////AA//gf//////+AA//gP//////+AA//gH//////8AA//gD//////4AA//gB//////wAA//gA//////AAAAAAAH////8AAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////gAAAAB///////+AAAAH////////gAAAf////////4AAB/////////8AAD/////////+AAH//////////AAH//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wAf//////////4A//wAD/4AAf/4A//gAH/wAAP/4A//gAH/wAAP/4A//gAP/wAAP/4A//gAP/4AAf/4A//wAP/+AD//4A///wP//////4Af//4P//////wAf//4P//////wAf//4P//////wAf//4P//////wAP//4P//////gAP//4H//////gAH//4H//////AAH//4D/////+AAD//4D/////8AAB//4B/////4AAA//4A/////wAAAP/4AP////AAAAB/4AD///4AAAAAAAAAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAADgA//gAAAAAAP/gA//gAAAAAH//gA//gAAAAB///gA//gAAAAP///gA//gAAAD////gA//gAAAf////gA//gAAB/////gA//gAAP/////gA//gAB//////gA//gAH//////gA//gA///////gA//gD///////gA//gf///////gA//h////////gA//n////////gA//////////gAA/////////AAAA////////wAAAA///////4AAAAA///////AAAAAA//////4AAAAAA//////AAAAAAA/////4AAAAAAA/////AAAAAAAA////8AAAAAAAA////gAAAAAAAA///+AAAAAAAAA///4AAAAAAAAA///AAAAAAAAAA//4AAAAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//gB///wAAAAP//4H///+AAAA///8P////gAAB///+f////4AAD///+/////8AAH/////////+AAH//////////AAP//////////gAP//////////gAf//////////gAf//////////wAf//////////wAf//////////wA///////////wA//4D//wAB//4A//wB//gAA//4A//gA//gAAf/4A//gA//AAAf/4A//gA//gAAf/4A//wB//gAA//4A///P//8AH//4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////gAP//////////gAP//////////AAH//////////AAD/////////+AAD///+/////8AAB///8f////wAAAf//4P////AAAAH//wD///8AAAAA/+AAf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//gAAAAAAAAB///+AA/+AAAAP////gA//wAAAf////wA//4AAB/////4A//8AAD/////8A//+AAD/////+A///AAH/////+A///AAP//////A///gAP//////A///gAf//////A///wAf//////A///wAf//////A///wAf//////A///wA///////AB//4A//4AD//AAP/4A//gAB//AAP/4A//gAA//AAP/4A//gAA/+AAP/4A//gAB/8AAP/4A//wAB/8AAf/4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH/////////+AAD/////////8AAB/////////4AAAf////////wAAAP////////AAAAB///////4AAAAAD/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAB/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("EiAnGicnJycnJycnEw=="), 78 + (scale << 8) + (1 << 16)); }; -/* -function Dial(dial) { - return { - "numeric": { - splash: function() { - - }, - start: function() { - }, - race: function() { - } - }, - "circle": { - start: function() { - }, - race: function() { - } - } - }[dial]; -} -*/ function Regattatimer() { return { + icons: { + "satellite": function() { + return hs.decompress(atob("jEYxH+AH4Ab6QIIBJAfNAAQtSC4gxSCwgYHHBYYMC6IYPC5AZOC8QYMC5YYLC5inSDH4waVbAYJCpgA/AAI=")); + }, + "battery": function() { + return hs.decompress(atob("jEYxH+AHHSAAgXmCgoaRC/4X/C/4X/C/4X/C64Ap")); + } + }, layout: undefined, + /* + layouts: { + idle: function() { + switch(settings.dial) { + case "Discs": + break; + case "Numeric": + default: + break; + } + }, + start: function(phase) { + switch(settings.dial) { + case "Discs": + break; + case "Numeric": + default: + break; + } + }, + race: function() { + + } + }, + */ mode: "idle", // idle, start, race" countdown: 300, // 5 minutes counter: undefined, interval: undefined, - raceTimeStart: undefined, - - // compass settings - calibrated: false, - directions: [ - "N", - // NNO: {22.5, 22.5}, - "NE", - // ONO: {67.5, 67.5}, - "E", - // OSO: {112.5, 112.5}, - "SE", - // SSO: {157.5, 157.5}, - "S", - // SSW: {202.5, 202.5}, - "SW", - // WSW: {247.5, 247.5}, - "W", - // WNW: {292.5, 292.5}, - "NW", - // NNW: {337.5, 337.5}, - ], - settings: Object.assign({ "debug": false, - "dial": "numeric", + "buzzer": true, + "dial": "Numeric", "gps": false, - "compass": false, + "record": false, + "theme": "Dark", "fgColor": "#FFFF00", "bgColor": "#000000" }, require('Storage').readJSON("regattatimer.json", true) || {}), translations: Object.assign({ "de": { - "speed": "FüG", + "speed": "FüG", // Fahrt über Grund "speed_unit": "kn" }, "en": { - "speed": "SOA", + "speed": "SOA", // SOA speed of advance "speed_unit": "kn" } }, require('Storage').readJSON("translations.json", true) || {}), + init: function() { + + if(this.settings.debug) { + this.countdown = 1; + } + + if(this.settings.theme == "Dark") { + this.settings.fgColor = "#FFFF00"; + this.settings.bgColor = "#000000"; + } + else { + this.settings.fgColor = "#000000"; + this.settings.bgColor = "#FFFF00"; + } + + Bangle.setLCDPower(1); + Bangle.setLCDTimeout(0); + /* + // in "idle", "start" or "stoped" mode, a button click (re)starts the countdown + // in "race" mode, a button click stops the counter + var onButtonClick = (function(ev) { + switch(this.mode) { + case "idle": + this.resetCounter(); + this.mode = "start"; + this.setLayoutStartMinSec(); + this.startCounter(); + this.interval = setInterval((function() { + this.startCounter(); + }).bind(this), 1000); + break; + case "stoped": + case "start": + this.resetCounter(); + this.setLayoutIdle(); + break; + case "race": + this.raceCounterStop(); + break; + } + }).bind(this); + + setWatch(onButtonClick, BTN1, true); + */ + + setWatch(this.onButtonClick.binf(this), BTN1, true); + + this.setLayoutIdle(); + }, + + onButtonClick: function(ev) { + switch(this.mode) { + case "idle": + this.resetCounter(); + this.mode = "start"; + this.setLayoutStartMinSec(); + this.startCounter(); + this.interval = setInterval((function() { + this.startCounter(); + }).bind(this), 1000); + break; + case "stoped": + case "start": + this.resetCounter(); + this.setLayoutIdle(); + break; + case "race": + this.raceCounterStop(); + break; + } + }, + + onGPS: function(fix) { + if(this.mode == "race") { + if(fix.fix && isFinite(fix.speed)) { + this.layout.clear(layout.speed); + this.layout.speed.label = fix.speed.toFixed(2); + this.layout.render(this.layout.speed); + } + this.layout.satellites.label = fix.satellites; + } + }, + translate: function(slug) { return this.translations[locale][slug]; }, - /** - * During the start phase, the the clock counts down 5 4 1 minutes. - * On button press, the countdown begins again. - */ + // during the start phase, the clock counts down 5 4 1 0 minutes + // a button click restarts the countdown startCounter: function() { this.counter --; @@ -98,16 +170,15 @@ function Regattatimer() { if(counterMinutes > 0) { this.layout.minutes.label = counterMinutes; - this.layout.seconds.label = "0".concat(this.counter - counterMinutes * 60).toString().slice(-2); + // this.layout.seconds.label = "0".concat(this.counter - counterMinutes * 60).toString().slice(-2); + this.layout.seconds.label = this.padZeroLeft(this.counter - counterMinutes * 60); this.layout.render(); } else { this.setLayoutStartSec(); - //this.layout.seconds.label = "0".concat(this.counter.toString()).slice(-2); this.layout.seconds.label = this.counter.toString(); this.layout.render(); } - // this keeps the watch LCD lit up g.flip(); } @@ -116,22 +187,23 @@ function Regattatimer() { this.raceCounterStart(); } }, - padZeroLeft: function(s) { - return "0".concat(s).slice(-2); + padZeroLeft: function(str) { + return str.toString().padStart(2, "0"); }, formatTime: function(time) { - var hours = parseInt(time / 3600); - var minutes = parseInt(time / 60); - var seconds = time - (minutes * 60); + var + minutes = parseInt(time / 60), + seconds = time - (minutes * 60); - return this.padZeroLeft(hours.toString()) - .concat(":") - .concat(this.padZeroLeft(minutes.toString())) - .concat(":") - .concat(this.padZeroLeft(seconds.toString())); + return this.padZeroLeft(parseInt(time / 3600)) + ":" + this.padZeroLeft(minutes) + ":" + this.padZeroLeft(seconds); }, raceCounter: function() { - Bangle.setLCDPower(1); + + if(this.counter % 60 == 0) { + this.layout.clear(this.layout.battery); + this.layout.battery.label = E.getBattery() + "%"; + this.layout.render(this.layout.battery); + } this.counter ++; @@ -155,38 +227,27 @@ function Regattatimer() { this.interval = undefined; } - Bangle.buzz(); + if(settings.buzzer) { + Bangle.buzz(); + } this.counter = 0; - // switch to race mode this.mode = "race"; this.setLayoutRace(); this.raceCounter(); - this.interval = setInterval((() => { + this.interval = setInterval((function() { this.raceCounter(); }).bind(this), 1000); }, - /** - * Show an initial splash screen - */ - /* - setLayoutSplash: function() { - g.clear(); - - (new Layout({ - type: "v", - bgCol: this.settings.bgColor, - c: [ - {type: "txt", font: "17%", label: ""}, - {type: "txt", font: "17%", col: this.settings.fgColor, label: "REGATTA\nTIMER"}, - {type: "txt", font: "6x8", col: this.settings.fgColor, label: "v0.1"}, - {type: "txt", font: "6x8", col: this.settings.fgColor, fillx: true, filly: true, pad: 4, label: "BUTTON PUSH -> start"}, - {type: "txt", font: "6x8", col: this.settings.fgColor, fillx: true, pad: 4, label: "(c) 2021-2023\nNaden Badalgogtapeh"} - ]}, {lazy:true})).render(); + resetCounter: function() { + if(this.interval) { + clearInterval(this.interval); + this.interval = undefined; + } + this.counter = this.countdown; }, - */ setLayoutIdle: function() { @@ -194,24 +255,26 @@ function Regattatimer() { this.mode = "idle"; - (new Layout({ + this.layout = new Layout({ type: "v", bgCol: this.settings.bgColor, c: [ { - type: "h", + type: "v", c: [ {type: "txt", font: "Anton", label: "5", col: this.settings.fgColor, id: "minutes", fillx: 1, filly: 1}, + {type: "txt", font: "20%", label: "--:--", col: this.settings.fgColor, id: "daytime", fillx: 1, filly: 1} ] } - ]}, {lazy:true})).render(); - }, - resetCounter: function() { - if(this.interval) { - clearInterval(this.interval); - this.interval = undefined; - } - this.counter = this.countdown; + ]}, {lazy: true}); + + this.interval = setInterval((function() { + this.layout.daytime.label = require("locale").time(new Date(), 1); + this.layout.render(); + + // keeps the watch screen lit up + g.flip(); + }).bind(this), 1000); }, setLayoutStartMinSec: function() { g.clear(); @@ -227,9 +290,8 @@ function Regattatimer() { {type: "txt", font: "Anton", label: "59", col: this.settings.fgColor, id: "seconds", fillx: 1, filly: 1}, ] } - ]}, {lazy:true}); - - //this.layout.render(); + ]}, {lazy: true} + ); }, setLayoutStartSec: function() { g.clear(); @@ -239,7 +301,7 @@ function Regattatimer() { bgCol: this.settings.bgColor, c:[ {type: "txt", font: "Anton", label: "", fillx: true, filly: true, col: this.settings.fgColor, id: "seconds"}, - ]}, {lazy:true}); + ]}, {lazy: true}); }, setLayoutRace: function() { g.clear(); @@ -249,105 +311,27 @@ function Regattatimer() { bgCol: this.settings.bgColor, c: [ {type: "txt", font: "20%", label: "00:00:00", col: this.settings.fgColor, pad: 4, filly: 1, fillx: 1, id: "racetime"}, - {type: "txt", font: "20%", label: "-", col: this.settings.fgColor, pad: 4, filly:1, fillx:1, id: "compass"}, + {type: "txt", font: "15%", label: "-", col: this.settings.fgColor, pad: 4, filly:1, fillx:1, id: "daytime"}, // horizontal {type: "h", c: [ - {type:"txt", font:"10%", label: this.translate("speed"), col: this.settings.fgColor, pad:4, fillx:1, filly:1}, - {type:"txt", font:"15%", label: "...", col: this.settings.fgColor, pad:4, fillx:1, filly:1, id: "speed"}, - {type:"txt", font:"10%", label: this.translate("speed_unit"), col: this.settings.fgColor, pad:4, fillx:1, filly:1}, + {type: "txt", font: "10%", label: this.translate("speed"), col: this.settings.fgColor, pad:4, fillx:1, filly:1}, + {type: "txt", font: "20%", label: "0", col: this.settings.fgColor, pad:4, fillx:1, filly:1, id: "speed"}, + {type: "txt", font: "10%", label: this.translate("speed_unit"), col: this.settings.fgColor, pad:4, fillx:1, filly:1}, ]}, {type: "h", c: [ - {type: "txt", font: "10%", label: "-", col: this.settings.fgColor, pad: 4, filly: 1, fillx: 1, id: "satellites"}, - {type: "txt", font: "10%", label: "00:00", col: this.settings.fgColor, pad: 4, filly: 1, fillx: 1, halign: 1, id: "daytime"}, + {type:"img", pad: 2, src: this.icons.satellite()}, + {type: "txt", font: "10%", label: "0", col: this.settings.fgColor, pad: 2, filly:1, id: "satellites"}, + // hacky, use empty element with fillx to push the other elments to the left an right side + {type: undefined, pad: 2, fillx: 1}, + {type:"img", pad: 2, src: this.icons.battery()}, + {type: "txt", font: "10%", label: "-", col: this.settings.fgColor, pad: 2, filly: 1, id: "battery"}, ]} - ]},{lazy:true}); - }, - onGPS: function(fix) { - if(this.mode == "race") { - if(fix.fix && isFinite(fix.speed)) { - this.layout.speed.label = fix.speed.toFixed(2); //m[1]; - } - this. layout.satellites.label = "Sats: ".concat(fix.satellites); - } - }, - /* - onCompass: function(data) { - - if(this.mode == "race") { - if(this.calibrated) { - this.layout.compass.label = this.directions[data.heading.toFixed(0) % 8]; - } - else { - this.layout.compass.label = "turn 360°"; - } - - var start = data.heading.toFixed(0) - 90; - - if(start<0) { - start += 360; - } - - var frag = 15 - start%15; - if (frag<15) {}else frag = 0; - var res = start + frag; - - var label = '?'; - - if(res%90==0){ - label = this.directions[Math.floor(res/45)%8]; - } else if (res%45==0) { - label = this.directions[Math.floor(res/45)%8]; - } - - //this.layout.compass.label = this.directions[data.heading.toFixed(0) % 8].concat(" ").concat(data.heading.toFixed(0).toString()) - this.layout.compass.label = label.concat(" ").concat(data.heading.toFixed(0).toString().concat("°")) - } - }, - */ - init: function() { - - if(this.settings.debug) { - this.countdown = 1; - } - - Bangle.setLCDPower(1); - Bangle.setLCDTimeout(0); - - this.setLayoutIdle(); - - var onButtonClick = ((ev) => { - - // "idle" or "start" mode, a button click (re)starts the start counter - switch(this.mode) { - case "idle": - this.resetCounter(); - this.mode = "start"; - this.setLayoutStartMinSec(); - this.startCounter(); - this.interval = setInterval((() => { - this.startCounter(); - }).bind(this), 1000); - break; - case "stoped": - case "start": - this.resetCounter(); - this.setLayoutIdle(); - break; - // "race" mode, a button click triggers a time snapshot and stops - case "race": - this.raceCounterStop(); - break; - } - - }).bind(this); - - setWatch(onButtonClick, BTN1, true); + ]}, {lazy: true}); } - } + }; } -var regattatimer = Regattatimer() - +var regattatimer = Regattatimer(); regattatimer.init(); if(regattatimer.settings.gps) { @@ -355,17 +339,12 @@ if(regattatimer.settings.gps) { Bangle.on('GPS', regattatimer.onGPS.bind(regattatimer)); } -if(regattatimer.settings.compass) { - Bangle.setCompassPower(1); - Bangle.on('mag', regattatimer.onCompass.bind(regattatimer)); -} +Bangle.on('kill', function() { + Bangle.setLCDPower(0); + Bangle.setLCDTimeout(10); -Bangle.on('kill',function() { if(regattatimer.settings.gps) { Bangle.setGPSPower(0); } - - if(regattatimer.settings.compass) { - Bangle.setCompassPower(0); - } }); + diff --git a/apps/regattatimer/icon.png b/apps/regattatimer/icon.png index 2f634774c..eb6057305 100644 Binary files a/apps/regattatimer/icon.png and b/apps/regattatimer/icon.png differ diff --git a/apps/regattatimer/metadata.json b/apps/regattatimer/metadata.json index d933af5d3..19c81f987 100644 --- a/apps/regattatimer/metadata.json +++ b/apps/regattatimer/metadata.json @@ -2,18 +2,17 @@ "id": "regattatimer", "name": "Regatta Timer", "shortName": "RegattaTimer", - "version": "0.2", + "version": "0.3", "description": "Regatta Timer with 5-4-1 Countdown", "icon": "icon.png", - "screenshots": [{"url":"screenshot.png"}], "tags": "tool,outdoors,sailing,race,regatta,boat,timer", "supports": ["BANGLEJS2"], "readme": "README.md", "storage": [ - {"name":"regattatimer.app.js","url":"app.js"}, - {"name":"regattatimer.settings.js","url":"settings.js"}, - {"name":"regattatimer.img","url":"app-icon.js","evaluate":true} + {"name": "regattatimer.app.js", "url": "app.js"}, + {"name": "regattatimer.settings.js", "url": "settings.js"}, + {"name": "regattatimer.img", "url": "app-icon.js", "evaluate": true}, ], "data": [{"name": "regattatimer.json"}], - "screenshots": [{"url":"screenshot.png"},{"url":"screenshot-1.png"},{"url":"screenshot-2.png"}] + "screenshots": [{"url": "screenshot.png"},{"url": "screenshot-1.png"},{"url": "screenshot-2.png"},{"url": "screenshot-3.png"},{"url": "screenshot-4.png"},{"url": "screenshot-5.png"},{"url": "screenshot-6.png"},{"url": "screenshot-7.png"}] } diff --git a/apps/regattatimer/regattatimer.json b/apps/regattatimer/regattatimer.json index baad5af42..c9ea85101 100644 --- a/apps/regattatimer/regattatimer.json +++ b/apps/regattatimer/regattatimer.json @@ -1,8 +1,10 @@ { "debug": false, - "dial": "numeric", + "buzzer": true, + "dial": "Numeric", "gps": false, - "compass": false, + "record": false, + "theme": "Dark", "fgColor": "#FFFF00", "bgColor": "#000000" } diff --git a/apps/regattatimer/screenshot-1.png b/apps/regattatimer/screenshot-1.png index a24bfa887..6888ccd62 100644 Binary files a/apps/regattatimer/screenshot-1.png and b/apps/regattatimer/screenshot-1.png differ diff --git a/apps/regattatimer/screenshot-2.png b/apps/regattatimer/screenshot-2.png index 932028ae0..bde59766d 100644 Binary files a/apps/regattatimer/screenshot-2.png and b/apps/regattatimer/screenshot-2.png differ diff --git a/apps/regattatimer/screenshot-3.png b/apps/regattatimer/screenshot-3.png new file mode 100644 index 000000000..4416a0fc8 Binary files /dev/null and b/apps/regattatimer/screenshot-3.png differ diff --git a/apps/regattatimer/screenshot-4.png b/apps/regattatimer/screenshot-4.png new file mode 100644 index 000000000..23cb79ac7 Binary files /dev/null and b/apps/regattatimer/screenshot-4.png differ diff --git a/apps/regattatimer/screenshot-5.png b/apps/regattatimer/screenshot-5.png new file mode 100644 index 000000000..49613d8c0 Binary files /dev/null and b/apps/regattatimer/screenshot-5.png differ diff --git a/apps/regattatimer/screenshot-6.png b/apps/regattatimer/screenshot-6.png new file mode 100644 index 000000000..eaa306ba4 Binary files /dev/null and b/apps/regattatimer/screenshot-6.png differ diff --git a/apps/regattatimer/screenshot-7.png b/apps/regattatimer/screenshot-7.png new file mode 100644 index 000000000..e1f96005f Binary files /dev/null and b/apps/regattatimer/screenshot-7.png differ diff --git a/apps/regattatimer/screenshot.png b/apps/regattatimer/screenshot.png index 32f1993b5..23cb79ac7 100644 Binary files a/apps/regattatimer/screenshot.png and b/apps/regattatimer/screenshot.png differ diff --git a/apps/regattatimer/settings.js b/apps/regattatimer/settings.js index 7466f0906..21922242b 100644 --- a/apps/regattatimer/settings.js +++ b/apps/regattatimer/settings.js @@ -1,52 +1,79 @@ (function(back) { - var file = "regattatimer.json"; - // Load settings - var settings = Object.assign({ - "debug": false, - "dial": "numeric", - "gps": false, - "compass": false, - "fgColor": "#FFFF00", - "bgColor": "#000000" - }, require('Storage').readJSON(file, true) || {}); + var + file = "regattatimer.json", - function writeSettings() { - require('Storage').writeJSON(file, settings); + storage = require("Storage"), + + dials = ["Numeric", "Discs"], + + themes = ["Light", "Dark"], + + settings = Object.assign({ + "debug": false, + "buzzer": true, + "dial": "Numeric", + "gps": false, + "record": false, + "theme": "Dark", + "fgColor": "#FFFF00", + "bgColor": "#000000" + }, storage.readJSON(file, true) || {}); + + function save(key, value) { + settings[key] = value; + storage.writeJSON(file, settings); } - // Show the menu E.showMenu({ "" : { "title" : "Regatta Timer" }, "< Back" : () => back(), - 'GPS': { + "GPS": { value: !!settings.gps, // !! converts undefined to false onchange: v => { - settings.gps = v; - writeSettings(); + save("gps", v); } }, - 'COMPASS': { - value: !!settings.compass, // 0| converts undefined to 0 - onchange: v => { - settings.compass = v; - writeSettings(); - } - }, - "DIAL": { - value: settings.dial, + "THEME": { + value: themes.indexOf(settings.theme), min: 0, - max: 1, - format: v => ["Numeric", "Disc"][v], - onchange: v => { - settings.dial = v; - writeSettings(); + max: themes.length - 1, + step: 1, + wrap: true, + format: v => themes[v], + onchange: (d) => { + save("theme", themes[d]); } }, - 'DEBUG': { + "BUZZER": { + value: !!settings.buzzer, // !! converts undefined to false + onchange: v => { + save("buzzer", v); + } + }, + /* + "DIAL": { + value: dials.indexOf(settings.dial), + min: 0, + max: dials.length - 1, + step: 1, + wrap: true, + format: v => dials[v], + onchange: (d) => { + save("dial", dials[d]); + } + }, + "RECORD": { + value: !!settings.record, // 0| converts undefined to 0 + onchange: v => { + settings.record = v; + save("record", v); + } + }, + */ + "DEBUG": { value: !!settings.debug, // 0| converts undefined to 0 onchange: v => { - settings.debug = v; - writeSettings(); + save("debug", v); } }, });