From 39e524f6f45463575431d64b9b9208825bb21feb Mon Sep 17 00:00:00 2001 From: naden Date: Fri, 23 Feb 2024 16:53:24 +0100 Subject: [PATCH] Add files via upload --- apps/regattatimer/README.md | 7 + apps/regattatimer/app-icon.js | 1 + apps/regattatimer/metadata.json | 18 + apps/regattatimer/regattatimer.app.js | 368 ++++++++++++++++++ apps/regattatimer/regattatimer.json | 8 + apps/regattatimer/regattatimer.settings.js | 46 +++ .../regattatimer.translations.json | 10 + apps/regattatimer/screenshot (1).png | Bin 0 -> 1950 bytes apps/regattatimer/screenshot (2).png | Bin 0 -> 2134 bytes apps/regattatimer/screenshot.png | Bin 0 -> 1805 bytes 10 files changed, 458 insertions(+) create mode 100644 apps/regattatimer/README.md create mode 100644 apps/regattatimer/app-icon.js create mode 100644 apps/regattatimer/metadata.json create mode 100644 apps/regattatimer/regattatimer.app.js create mode 100644 apps/regattatimer/regattatimer.json create mode 100644 apps/regattatimer/regattatimer.settings.js create mode 100644 apps/regattatimer/regattatimer.translations.json create mode 100644 apps/regattatimer/screenshot (1).png create mode 100644 apps/regattatimer/screenshot (2).png create mode 100644 apps/regattatimer/screenshot.png diff --git a/apps/regattatimer/README.md b/apps/regattatimer/README.md new file mode 100644 index 000000000..f838ee9c0 --- /dev/null +++ b/apps/regattatimer/README.md @@ -0,0 +1,7 @@ +require("locale").name + +Go to: https://banglejs.com/apps/ +Search for app: Languages +Click The arrow Up or burger icon +Choose your language fro the dropdown +click "upload" diff --git a/apps/regattatimer/app-icon.js b/apps/regattatimer/app-icon.js new file mode 100644 index 000000000..0d5ffe739 --- /dev/null +++ b/apps/regattatimer/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mUvgP/AAM/AYQAB54FE8YFE/GfAof+kYMEhF/AofCh4FD8mBAof5mQyD/nM44kDmc4CQec54SD58zCQfj5n4Egfzn4SC/n85/nEgU/mf5CQUf5hrDx4YBNYXH/mPCQRuBk/+LwPx//JCoJ0B//yv/zAoN//kf/g2BE4JvBAYMD//D/4+B+Ef+BNBFYOA/kDFYX+g8wh6dC+EP4EnCILDDj/AAocHHIIAC+I5BXoZoBTwd/ZYZ5BA4IFCCAOHAonwIARYB/sH3/2hwgBgED+EOIwMggkAwEQgE+g/A/Efg/9/+/+/+DAMfwfwvwYMggA=")) diff --git a/apps/regattatimer/metadata.json b/apps/regattatimer/metadata.json new file mode 100644 index 000000000..00da0c0e3 --- /dev/null +++ b/apps/regattatimer/metadata.json @@ -0,0 +1,18 @@ +{ + "id": "regattatimer", + "name": "Regatta Timer", + "shortName": "Regatta Timer", + "version": "0.1", + "description": "Regatta Timer with classic 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} + ], + "data": [{"name": "regattatimer.json"}] +} diff --git a/apps/regattatimer/regattatimer.app.js b/apps/regattatimer/regattatimer.app.js new file mode 100644 index 000000000..90fb908b8 --- /dev/null +++ b/apps/regattatimer/regattatimer.app.js @@ -0,0 +1,368 @@ +/** + * Regatta Timer + * + */ +const DEBUG = true; +const Layout = require("Layout"); +const locale = require("locale").name.substring(0, 2); + +// "Anton" bold font +Graphics.prototype.setFontAnton = function(scale) { + // Actual height 69 (68 - 0) + 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 { + layout: undefined, + mode: "idle", // idle, start, race" + countdown: DEBUG ? 1 : 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({ + "dial": "numeric", + "gps": false, + "compass": false, + "language": "en", + "fgColor": "#FFFF00", + "bgColor": "#000000" + }, require('Storage').readJSON("regattatimer.json", true) || {}), + + translations: Object.assign({ + "de": { + "speed": "FüG", + "speed_unit": "kn" + }, + "en": { + "speed": "SOA", + "speed_unit": "kn" + } + }, require('Storage').readJSON("translations.json", true) || {}), + + translate: function(slug) { + return this.translations[this.settings.language][slug]; + }, + /** + * During the start phase, the the clock counts down 5 4 1 minutes. + * On button press, the countdown begins again. + */ + startCounter: function() { + + this.counter --; + + if(this.counter >= 0) { + var counterMinutes = parseInt(this.counter / 60); + + if(counterMinutes > 0) { + this.layout.minutes.label = counterMinutes; + this.layout.seconds.label = "0".concat(this.counter - counterMinutes * 60).toString().slice(-2); + 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(); + } + // time is up + else { + this.raceCounterStart(); + } + }, + padZeroLeft: function(s) { + return "0".concat(s).slice(-2); + }, + formatTime: function(time) { + var hours = parseInt(time / 3600); + var minutes = parseInt(time / 60); + var seconds = time - (minutes * 60); + + return this.padZeroLeft(hours.toString()) + .concat(":") + .concat(this.padZeroLeft(minutes.toString())) + .concat(":") + .concat(this.padZeroLeft(seconds.toString())); + }, + raceCounter: function() { + Bangle.setLCDPower(1); + + this.counter ++; + + this.layout.racetime.label = this.formatTime(this.counter); + this.layout.daytime.label = require("locale").time(new Date(), 1); + this.layout.render(); + + // keeps the watch screen lit up + g.flip(); + }, + raceCounterStop: function() { + if(this.interval) { + clearInterval(this.interval); + this.interval = undefined; + } + this.mode = "stoped"; + }, + raceCounterStart: function() { + if(this.interval) { + clearInterval(this.interval); + this.interval = undefined; + } + + Bangle.buzz(); + + this.counter = 0; + + // switch to race mode + this.mode = "race"; + this.setLayoutRace(); + this.raceCounter(); + this.interval = setInterval((() => { + 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.2"}, + {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(); + }, + */ + + setLayoutIdle: function() { + + g.clear(); + + this.mode = "idle"; + + (new Layout({ + type: "v", + bgCol: this.settings.bgColor, + c: [ + { + type: "h", + c: [ + {type: "txt", font: "Anton", label: "5", col: this.settings.fgColor, id: "minutes", fillx: 1, filly: 1}, + ] + } + ]}, {lazy:true})).render(); + }, + resetCounter: function() { + if(this.interval) { + clearInterval(this.interval); + this.interval = undefined; + } + this.counter = this.countdown; + }, + setLayoutStartMinSec: function() { + g.clear(); + + this.layout = new Layout({ + type: "v", + bgCol: this.settings.bgColor, + c: [ + { + type: "h", + c: [ + {type: "txt", font: "Anton", label: "4", col: this.settings.fgColor, id: "minutes", fillx: 1, filly: 1}, + {type: "txt", font: "Anton", label: "59", col: this.settings.fgColor, id: "seconds", fillx: 1, filly: 1}, + ] + } + ]}, {lazy:true}); + + //this.layout.render(); + }, + setLayoutStartSec: function() { + g.clear(); + + this.layout = new Layout({ + type: "v", + bgCol: this.settings.bgColor, + c:[ + {type: "txt", font: "Anton", label: "", fillx: true, filly: true, col: this.settings.fgColor, id: "seconds"}, + ]}, {lazy:true}); + }, + setLayoutRace: function() { + g.clear(); + + this.layout = new Layout({ + type: "v", + 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"}, + // 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: "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"}, + ]} + + ]},{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 = "Satellites ".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() { + + this.setLayoutIdle(); + + Bangle.setLCDPower(1); + + 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); + } + } +} + +var regattatimer = Regattatimer() + +regattatimer.init(); + +if(regattatimer.gps) { + Bangle.setGPSPower(1); + Bangle.on('GPS', regattatimer.onGPS.bind(regattatimer)); +} + +if(regattatimer.compass) { + Bangle.setCompassPower(1); + Bangle.on('mag', regattatimer.onCompass.bind(regattatimer)); +} + +Bangle.on('kill',function() { + if(regattatimer.gps) { + Bangle.setGPSPower(0); + } + + if(regattatimer.compass) { + Bangle.setCompassPower(0); + } +}); diff --git a/apps/regattatimer/regattatimer.json b/apps/regattatimer/regattatimer.json new file mode 100644 index 000000000..3f81dedb5 --- /dev/null +++ b/apps/regattatimer/regattatimer.json @@ -0,0 +1,8 @@ +{ + "dial": "numeric", + "gps": false, + "compass": false, + "language": "en", + "fgColor": "#FFFF00", + "bgColor": "#000000" +} diff --git a/apps/regattatimer/regattatimer.settings.js b/apps/regattatimer/regattatimer.settings.js new file mode 100644 index 000000000..8e177a1a4 --- /dev/null +++ b/apps/regattatimer/regattatimer.settings.js @@ -0,0 +1,46 @@ +(function(back) { + var file = "regattatimer.json"; + // Load settings + var settings = Object.assign({ + "dial": "numeric", + "gps": false, + "compass": false, + "language": "en", + "fgColor": "#FFFF00", + "bgColor": "#000000" + }, require('Storage').readJSON(file, true) || {}); + + function writeSettings() { + require('Storage').writeJSON(file, settings); + } + + // Show the menu + E.showMenu({ + "" : { "title" : "Regatta Timer" }, + "< Back" : () => back(), + 'GPS': { + value: !!settings.gps, // !! converts undefined to false + onchange: v => { + settings.gps = v; + writeSettings(); + } + }, + 'COMPASS': { + value: !!settings.gps, // 0| converts undefined to 0 + onchange: v => { + settings.compass = v; + writeSettings(); + } + } + "DIAL": { + value: settings.dial, + min: 0, + max: 1, + format: v => ["Numeric", "Disc"][v], + onchange: v => { + settings.dial = v; + writeSettings(); + } + } + }); +}) diff --git a/apps/regattatimer/regattatimer.translations.json b/apps/regattatimer/regattatimer.translations.json new file mode 100644 index 000000000..e89eeddf8 --- /dev/null +++ b/apps/regattatimer/regattatimer.translations.json @@ -0,0 +1,10 @@ +{ + "de": { + "speed": "FüG", + "speed_unit": "kn" + }, + "en": { + "speed": "SOA", + "speed_unit": "kn" + } +} diff --git a/apps/regattatimer/screenshot (1).png b/apps/regattatimer/screenshot (1).png new file mode 100644 index 0000000000000000000000000000000000000000..a24bfa88715623b1386413c57d99fca915c501c9 GIT binary patch literal 1950 zcmds&{X5j@9>=F|x6G)l`C5{b$C>e%v1(cJxWiyp6w-Pa)2z~*4K)&t#;R`}i%f%= zhFDZ=2w|O!hsf8S9vq6}gl3zV*~#P42&Gh({nqaJ56(~Lhx>kiuGf9tpZDjwulIG` z*?WWhHftGb;c&Rk41b>xOdCHe{03}qXc=c=vMwpakA|!7-!_B8X@)a=zTC%SsY?cr zKXcv$Bx`HaOqZzJOYPf=lw2HbuA|;-@56qBk$bDVgwNh9HK9O4ni=<4K)A9&Y06QF6F zf)tuW^ST2l+{#umSLPVd9SiF73W3ylYvj#NG)yHz%?9GPwCJ}+vS8Wd#Qe{88e?BF zVV=xkHbV`@7#RJ}f-9r$M! zO3gU(xU&T9>im(!z46!jxk7k3-k8oVq&3g7Xv+LALhwx6;#xi*@f+{#_WsDFdc1v4 zU0I-B@8NLgH8ePt!7lVznw7#lUnVy4jw$UY_`03|$W^Z<8oT&mkjU<*qb>S8Ne8(x zs-k_V+eRznv98RkO}DOTF)7&n8)2-jPZ8U@6y)Whn(0GZT2+;-rSSpl zlP=lK@4eXhQ`!wwmEBFMAA4b0CmdK6kQ%k-ee*8wfbiSPEfM;e7#FA($6)7Q*)K#5 zyDGe)hIB}`bL#8gD&kgBcH;%;H&Dgmg%y>cJ_A+!nq+9R_Y-z?Hg7P?KVSdFTxzA_ zmLt&sAqmS^vnyH+)ja|o)la@ij=Hj!125DOp*=?D_TPM`^WxTwP2)jDmqYsS>~lAB zJ_%`74g@zt`z~fnBuI3%@8e9Ie@>sd zI%LirzsO?dpr@}`!8XnKm0uy-MYrDf5Wp54RHuZFEpCD_eV=muMnJ;#0vpCfg zbL;x?C8BED-B*!EZ#bR&67P2Hj-q_chq+0^@XDkhu1uI#`O8Q^o5n4V(l*QDF z7K5$*8u-b&U)e!9k*4z|XU_i(D@pU#NN}5P0|~Lr2vr!ZjYz$rfnL2-v1IVv7m4D< z%aUXr-Xz7t{KfOXG!+>SaJunkUyVj6i=s}ZUwL`^GCmZPx!lbx#>f98Vb%+SNpFe= zpAi9OA=p+Ui-}16p1IXshgSr#USazofI3W~- zq1@Jdygd)K=*RkRC+vo%swIyyfK#FcX3k*4&VDyasAR4-r`?Nfz3#o`j)J*@yQcGQ zyNvEHY}Uh{pm;$i-CbUnzO>Np*WtpZNa=|Pc@Pd!XML+ApFxA#>k=%_pec7g=fYlW z%jglQt{2-i#?YBy+9;;R$uTi<*jxg1WQ@XQH73GK8-gJG^B?=3q(Jz1zuoIC*MXFO z$0oS015#2YBE~_kGfmP`93&?`LK(O}?3A8je}PHhp*|1n!^JV^K|b{~_SxS7D)VLU literal 0 HcmV?d00001 diff --git a/apps/regattatimer/screenshot (2).png b/apps/regattatimer/screenshot (2).png new file mode 100644 index 0000000000000000000000000000000000000000..932028ae09d44ca916be36d5bcf4c7ee901ed26d GIT binary patch literal 2134 zcmd6p`!kz~8pnw@q)A(e5-m~@TP+f2jUJalf{n&)>)Hq@O|46}i%{1bT79uDQN*q| zt)i-SP^m<86N{~sQfKSZ3zZzUf~ZqP+*7T~vH!*X@I0TH&&+q`ndkZCDfBx}IRZC; ztEs6S@$?`E98mCA!88v#U#ti}fO=8@#Z9ec*yw|r8Vu=4b`44oU#j-McG2!I@XHtD z|C*aqar`tW$LJ;?-P1Fks%_A(5C?EoVzKxVa|d+shbUneA3H>3>9{b+XTDVfy~io( zKtK2zK(;4e&!sSo{_Zjl*z4Or`u=;F(pVR<%9}Q@LX3SmaZ{!zuVGg z-bFrOrnNkbzm9#o@ruVnrgz|$a@aj-%y&w%?t12A%uuc*RJ(y0s2k69#>CIK_Bp|v z)NhQNvU^a{D||ymn2?ykv=gyeQpxEP|B_vEk-M##*IB^lg9~1Wa^0N9FtDAf`px?a zI*bbzsjy!|{$cT0l?cS+1a$+-GraEXt*c-5C-jo;oo$Y&37B$g)Vy&@;W@YV&&sSg z+V64u82ivkN)Q@J3SIJq=KmZWIGD7dNj+lU{K_*bYp_A*#oCQRX((GcS zYxU}w4@ySaULrDEiCzrLMf@NPRVTc0&l;z~_lAvxRF$Hn@D8{i;hW@leAd`+!4Ai?Mu`_LeCnZ|+gk3Wg{_rN85kWwtgtq2UVNDNnWSHx#H*MoYKqWMr2 zdJw$YznX*)&azibE$*Mpc~Tj+Nh~5j5TmVFM7T*O&YQWR*ygSSoipL<~wB>MVJvG7|)%67Qy!cSxc$>DCkvSgWO!;pVX}o^=S3GEIN7uq!g2se7*bGvc`B$t*SMb67e5Fp_98|5$>e(+G(GBc(q$n-UouKU0ut6I*&LJ^H&S;)8PR zdfJxHxi)3x<<74XM$t7;&g$f0h3uj~J>J%LBgrNfm0rs|A<-D$PuVa7V`Nr{%s1$o zA8$Rg1w%xz*tT6KYlM`w`{Fyh*l9hH4#<@DSaQlf#Xu|%4s&@N&Un80zHFGD&VA$~ zKY*U_`^H(9;KE=TPGB-(!N|YcVv2!M1zh;f7+GHmmsmM!9eujxOEZB4>u-}2jWK)+ zVP#ySWQZ^$Kij?>d?rVRyEeW^u~ zPWR#L&e+)=XeW6%y7PiOwybU1>eK0rv)+oZ*ixi@s3I&O3Jten>#*!59sty$F2fdy zhh^H@Ma!gh*&f;nvaDtlgoB_+EjKnpN<)X27*2f`JuaYLr qQSEWRrX9|cq-{*5di~8KyBhT-a$~KMDa65}pyug*p4{Tb$o@a%)!qOA literal 0 HcmV?d00001 diff --git a/apps/regattatimer/screenshot.png b/apps/regattatimer/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..32f1993b534e69630a0c0404656a1e8522229f61 GIT binary patch literal 1805 zcmbtVX;_n28ol`v0$~$~ECH%wAX)@W*;O_vi`p2#Q3-o20u`tP5eWj4XaPrur8PjJ z5Qh2?nW7;Dg#ao25L%E$Y-!69mK36tB_RZ2SSn6tp7}Gs`{Ug6yzhC>x%ba~-oJ;E zgAH^obpZedCr<>N(Xik@&_Qd?##U*ph7cKNg8c#irS$>;=-!h7$IsGZWm7+0+kZ?y zAWZpwZ}ns11v}!@Y4H>LPu_Ay^;)7QKGV0&@V(qBo-g*b4RvMi0_HO7gc&R#8l5@- zBtOd@(n0(`uR_3S%IA(Y5&f5&0+b|V_3-Ju+(&&iHW-ot#X$Wm-tVmy*F<3DRQ8Ux z_ZV4=?i#&s+a?6zX{F(PmFTJuoXS*XpFn)HdEe2#IuKr@C#Cna z??BYCVSuKs#AS3NZmFY}gr}B8!4~h{_W>ef*sjcoNEb);?%wfjtPR%zNTDM$fYBu$ zJ<3yLT<#_i8HmYBKM1}oTKt!rID0>}?KcZ&X0<{1T%K$4k1lOSvE#jl^fy7nxh;qK zSi{w3f)r(^dv5{#mra&M&TlPHY+YMJRkL>VdIk?!mEe5DDCtOwYk!3*l@Xr$$DO3h zUFNG}mq1c=P;yVi@CVGbK}$2Z!6RL@R>K_IW-A#DqN4Y2JQsc)+|5LGJY|X?4 z7v@|ynwHBWQR8{Qy>JLsvdc=7;>`R%b9>uX51R;zQYLIS^Ci~g)S z3DR3THy4w)H9hRRHKT2|g==@Ed#@rXWzEQyzJ-p=&M-9%Xd}6}6;5-T4bsy{!9fRq zKL5qf8BXDOz|iE^5$W`k7|+h7j_XdDPk{W~`h0fygUQI7mOso~=W|cT9AZSNL|!|| zx1w6ZZ+YIzYAAeY&2mEu&%J_QEbT~ZRU?JoJ)o08Qk_*xhf366Hd}p!6^3o-2un@M z?>+vgu)C<0EI*Wk6xw(zxO#f<{FNr3WZPJ^>i1*;=)6yrtOa*#t)#oO`CCixA=2z% zxd%<1x^e00=UtMi{Djtv4{yw2BwcYNQHQJ^Arj{=eUB6#aO=*9w2VJ^K-Q>RJ@jIA zHXeF^!b`kcdvdvEyX9hCkjP6?k;qWTL5>^*rJh%3{M?yaao!_3+t8;Vl=tAzp~$+@ zfszU7pC<7yN`G=DPemwvsK<;CXKKH^-Ks3VkY<9U(8@vMzF(^C5Z3I>AfYK=|2v(j zG%2ss|6)(nLjS8fW5rpE9_fr1ly*yH0pe?-3LXSs!_+8#l< zZmC+ROr)tBl2X0+B#g!>X=H={ zYS{|jPK1u)&CRc#-PgPbAI;Z~*d%OMW;@Tm?k_V>Yd;j=4oilLJxr;JH@#nd``k54 z;=tgv<2dqB7DS|{)V?_D$jEQ+k`DDKa~-=8rQA-~yVPzDUy0VA{)eqN*;1D-UDryp zVm&U6H6+rS&n!2jSV)XV%td)8oPASpn)E@z_boPzDNXC0Uz0Bu9zPb4SA-cuxa1k* zIDmm4x#*Y!org(rIr)!fjNp-0x*RzHT=M1%T^Fx{J>_28g|<}0;JU$r>D^RYK&7zA zeunIYsEOdM*+Bd`nF z;DRh_>ETT$5;d$x0|ALj5ENA;nG*yDlQf_Zh}f}@2b%S;8UvQH+X2hQEZ4psFTgnT zb1)9N6_`QP+gHlv=P0w+gD5kt0aPNC^I7(_3((ywiO}7f36KlZ`>9t4kr{Zzg&El8 z%;dm(BDpba`0FYT{56#Wlc>8Khc(xSyj=E&YB7EJc>L2yGdy#&VMKOq+t$>i{yxA8 zljrNjYlM=jlYSh4rEr{52CzWj^{IO(0ZXlKgm$X1{@xf#d+bKlSFn0q{XK;{X5v literal 0 HcmV?d00001