diff --git a/apps/accellog/ChangeLog b/apps/accellog/ChangeLog index 80981fe27..94241c7a7 100644 --- a/apps/accellog/ChangeLog +++ b/apps/accellog/ChangeLog @@ -2,3 +2,4 @@ 0.02: Use the new multiplatform 'Layout' library 0.03: Exit as first menu option, dont show decimal places for seconds 0.04: Localisation, change Exit->Back to allow back-arrow to appear on 2v13 firmware +0.05: Add max G values during recording, record actual G values and magnitude to CSV diff --git a/apps/accellog/app.js b/apps/accellog/app.js index f4c1b3c5a..147f7503f 100644 --- a/apps/accellog/app.js +++ b/apps/accellog/app.js @@ -1,5 +1,6 @@ var fileNumber = 0; var MAXLOGS = 9; +var logRawData = false; function getFileName(n) { return "accellog."+n+".csv"; @@ -24,6 +25,11 @@ function showMenu() { /*LANG*/"View Logs" : function() { viewLogs(); }, + /*LANG*/"Log raw data" : { + value : logRawData, + format : v => v?/*LANG*/"Yes":/*LANG*/"No", + onchange : v => { logRawData=v; } + }, }; E.showMenu(menu); } @@ -78,6 +84,7 @@ function viewLogs() { } function startRecord(force) { + var stopped = false; if (!force) { // check for existing file var f = require("Storage").open(getFileName(fileNumber), "r"); @@ -92,39 +99,101 @@ function startRecord(force) { var Layout = require("Layout"); var layout = new Layout({ type: "v", c: [ - {type:"txt", font:"6x8", label:/*LANG*/"Samples", pad:2}, - {type:"txt", id:"samples", font:"6x8:2", label:" - ", pad:5, bgCol:g.theme.bg}, - {type:"txt", font:"6x8", label:/*LANG*/"Time", pad:2}, - {type:"txt", id:"time", font:"6x8:2", label:" - ", pad:5, bgCol:g.theme.bg}, - {type:"txt", font:"6x8:2", label:/*LANG*/"RECORDING", bgCol:"#f00", pad:5, fillx:1}, - ] - },{btns:[ // Buttons... - {label:/*LANG*/"STOP", cb:()=>{ - Bangle.removeListener('accel', accelHandler); - showMenu(); + { type: "h", c: [ + { type: "v", c: [ + {type:"txt", font:"6x8", label:/*LANG*/"Samples", pad:2}, + {type:"txt", id:"samples", font:"6x8:2", label:" - ", pad:5, bgCol:g.theme.bg}, + ]}, + { type: "v", c: [ + {type:"txt", font:"6x8", label:/*LANG*/"Time", pad:2}, + {type:"txt", id:"time", font:"6x8:2", label:" - ", pad:5, bgCol:g.theme.bg}, + ]}, + ]}, + { type: "h", c: [ + { type: "v", c: [ + {type:"txt", font:"6x8", label:/*LANG*/"Max X", pad:2}, + {type:"txt", id:"maxX", font:"6x8", label:" - ", pad:5, bgCol:g.theme.bg}, + ]}, + { type: "v", c: [ + {type:"txt", font:"6x8", label:/*LANG*/"Max Y", pad:2}, + {type:"txt", id:"maxY", font:"6x8", label:" - ", pad:5, bgCol:g.theme.bg}, + ]}, + { type: "v", c: [ + {type:"txt", font:"6x8", label:/*LANG*/"Max Z", pad:2}, + {type:"txt", id:"maxZ", font:"6x8", label:" - ", pad:5, bgCol:g.theme.bg}, + ]}, + ]}, + {type:"txt", font:"6x8", label:/*LANG*/"Max G", pad:2}, + {type:"txt", id:"maxMag", font:"6x8:4", label:" - ", pad:5, bgCol:g.theme.bg}, + {type:"txt", id:"state", font:"6x8:2", label:/*LANG*/"RECORDING", bgCol:"#f00", pad:5, fillx:1}, + ]}, + { + btns:[ // Buttons... + {id: "btnStop", label:/*LANG*/"STOP", cb:()=>{ + if (stopped) { + showMenu(); + } + else { + Bangle.removeListener('accel', accelHandler); + layout.state.label = /*LANG*/"STOPPED"; + layout.state.bgCol = /*LANG*/"#0f0"; + stopped = true; + layout.render(); + } }} ]}); layout.render(); // now start writing var f = require("Storage").open(getFileName(fileNumber), "w"); - f.write("Time (ms),X,Y,Z\n"); + f.write("Time (ms),X,Y,Z,Total\n"); var start = getTime(); var sampleCount = 0; + var maxMag = 0; + var maxX = 0; + var maxY = 0; + var maxZ = 0; function accelHandler(accel) { var t = getTime()-start; - f.write([ - t*1000, - accel.x*8192, - accel.y*8192, - accel.z*8192].map(n=>Math.round(n)).join(",")+"\n"); + if (logRawData) { + f.write([ + t*1000, + accel.x*8192, + accel.y*8192, + accel.z*8192, + accel.mag*8192, + ].map(n=>Math.round(n)).join(",")+"\n"); + } else { + f.write([ + Math.round(t*1000), + accel.x, + accel.y, + accel.z, + accel.mag, + ].join(",")+"\n"); + } + if (accel.mag > maxMag) { + maxMag = accel.mag.toFixed(2); + } + if (accel.x > maxX) { + maxX = accel.x.toFixed(2); + } + if (accel.y > maxY) { + maxY = accel.y.toFixed(2); + } + if (accel.z > maxZ) { + maxZ = accel.z.toFixed(2); + } sampleCount++; layout.samples.label = sampleCount; layout.time.label = Math.round(t)+"s"; - layout.render(layout.samples); - layout.render(layout.time); + layout.maxX.label = maxX; + layout.maxY.label = maxY; + layout.maxZ.label = maxZ; + layout.maxMag.label = maxMag; + layout.render(); } Bangle.setPollInterval(80); // 12.5 Hz - the default diff --git a/apps/accellog/metadata.json b/apps/accellog/metadata.json index fdf6cf320..903c57903 100644 --- a/apps/accellog/metadata.json +++ b/apps/accellog/metadata.json @@ -2,7 +2,7 @@ "id": "accellog", "name": "Acceleration Logger", "shortName": "Accel Log", - "version": "0.04", + "version": "0.05", "description": "Logs XYZ acceleration data to a CSV file that can be downloaded to your PC", "icon": "app.png", "tags": "outdoor", diff --git a/apps/agenda/README.md b/apps/agenda/README.md index 7063a70a2..1a0ec9264 100644 --- a/apps/agenda/README.md +++ b/apps/agenda/README.md @@ -10,11 +10,21 @@ Basic agenda reading the events synchronised from GadgetBridge. * Show the colour of the calendar in the list * Display description, location and calendar name after tapping on events +### Troubleshooting + +For the events sync to work, GadgetBridge needs to have the calendar permission and calendar sync should be enabled in the devices settings (gear sign in GB, also check the blacklisted calendars there, if events are missing). +Keep in mind that GadgetBridge won't synchronize all events on your calendar, just the ones in a time window of 7 days (you don't want your watch to explode), ideally every day old events get deleted since they appear out of such window. + +#### Force Sync + +If for any reason events still cannot sync or some are missing, you can try any of the following (just one, you normally don't need to do this): +1. from GB open the burger menu (side), tap debug and set time. +2. from the bangle, open settings > apps > agenda > Force calendar sync, then select not to delete the local events (this is equivalent to option 1). +3. do like option 2 but delete events, GB will synchronize a fresh database instead of patching the old one (good in case you somehow cannot get rid of older events) + +After any of the options, you may need to disconnect/force close Gadgetbridge before reconnecting and let it sync (give it some time for that too), restart the agenda app on the bangle after a while to see the changes. + ### Report a bug You can easily open an issue in the espruino repo, but I won't be notified and it might take time. If you want a (hopefully) quicker response, just report [on my fork](https://github.com/glemco/BangleApps). - -### Known Problems - -Any all-day event lasts just one day: that is a GB limitation that we will likely fix in the future. diff --git a/apps/gpsnav/ChangeLog b/apps/gpsnav/ChangeLog index 6f327f364..840f9ecbc 100644 --- a/apps/gpsnav/ChangeLog +++ b/apps/gpsnav/ChangeLog @@ -4,4 +4,5 @@ 0.04: Fix great circle formula 0.05: Use locale for speed and distance + fix Vector font sizes 0.06: Move waypoints.json (and editor) to 'waypoints' app -0.07: Add support for b2 \ No newline at end of file +0.07: Add support for b2 +0.08: Fix not displaying of wpindex = 0, correct compass drawing and nm calculation on b2 diff --git a/apps/gpsnav/app.js b/apps/gpsnav/app.js index e2b6ee6f1..68bd2cbda 100644 --- a/apps/gpsnav/app.js +++ b/apps/gpsnav/app.js @@ -36,7 +36,7 @@ function drawCompass(course) { } xpos+=15; } - if (wpindex!=0) { + if (wpindex>=0) { var bpos = brg - course; if (bpos>180) bpos -=360; if (bpos<-180) bpos +=360; @@ -220,7 +220,7 @@ function nextwp(inc){ } function doselect(){ - if (selected && wpindex!=0 && waypoints[wpindex].lat===undefined && savedfix.fix) { + if (selected && wpindex>=0 && waypoints[wpindex].lat===undefined && savedfix.fix) { waypoints[wpindex] ={name:"@"+wp.name, lat:savedfix.lat, lon:savedfix.lon}; wp = waypoints[wpindex]; require("waypoints").save(waypoints); diff --git a/apps/gpsnav/app_b2.js b/apps/gpsnav/app_b2.js index e46be649f..ee6519c92 100644 --- a/apps/gpsnav/app_b2.js +++ b/apps/gpsnav/app_b2.js @@ -13,7 +13,7 @@ var loc = { distance: [ require("locale").distance, (m) => { - return (m / 1.852).toFixed(3) + "nm "; + return (m / 1852).toFixed(3) + "nm "; } ] }; @@ -21,7 +21,7 @@ var loc = { function drawCompass(course) { if (!candraw) return; - g.setColor(g.theme.fg); + g.reset().clearRect(0, 24, 175, 71); g.setFont("Vector", 18); var start = course - 90; if (start < 0) start += 360; @@ -43,7 +43,7 @@ function drawCompass(course) { } xpos += 12; } - if (wpindex != 0) { + if (wpindex >= 0) { var bpos = brg - course; if (bpos > 180) bpos -= 360; if (bpos < -180) bpos += 360; @@ -106,9 +106,8 @@ function distance(a, b) { var selected = false; function drawN() { - g.clearRect(0, 89, 175, 175); + g.reset().clearRect(0, 89, 175, 175); var txt = loc.speed[locindex](speed); - g.setColor(g.theme.fg); g.setFont("6x8", 2); g.drawString("o", 68, 87); g.setFont("6x8", 1); @@ -117,10 +116,8 @@ function drawN() { var cs = course.toString().padStart(3, "0"); g.drawString(cs, 2, 89); g.drawString(txt.substring(0, txt.length - 3), 92, 89); - g.setColor(g.theme.fg); g.setFont("Vector", 18); var bs = brg.toString().padStart(3, "0"); - g.setColor(g.theme.fg); g.drawString("Brg:", 1, 128); g.drawString("Dist:", 1, 148); g.setColor(selected ? g.theme.bgH : g.theme.bg); @@ -241,7 +238,7 @@ function nextwp(inc) { } function doselect() { - if (selected && wpindex != 0 && waypoints[wpindex].lat === undefined && savedfix.fix) { + if (selected && wpindex >= 0 && waypoints[wpindex].lat === undefined && savedfix.fix) { waypoints[wpindex] = { name: "@" + wp.name, lat: savedfix.lat, @@ -265,4 +262,4 @@ drawAll(); startTimers(); Bangle.on('GPS', onGPS); // Toggle selected -setButtons(); \ No newline at end of file +setButtons(); diff --git a/apps/gpsnav/metadata.json b/apps/gpsnav/metadata.json index dce80112f..bc46a733c 100644 --- a/apps/gpsnav/metadata.json +++ b/apps/gpsnav/metadata.json @@ -1,7 +1,7 @@ { "id": "gpsnav", "name": "GPS Navigation", - "version": "0.07", + "version": "0.08", "description": "Displays GPS Course and Speed, + Directions to waypoint and waypoint recording, now with waypoint editor", "screenshots": [{"url":"screenshot-b2.png"}], "icon": "icon.png", diff --git a/apps/gpstrek/ChangeLog b/apps/gpstrek/ChangeLog index 5560f00bc..2f1a9ce45 100644 --- a/apps/gpstrek/ChangeLog +++ b/apps/gpstrek/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Make selection of background activity more explicit diff --git a/apps/gpstrek/README.md b/apps/gpstrek/README.md index eecf4d087..439b7497a 100644 --- a/apps/gpstrek/README.md +++ b/apps/gpstrek/README.md @@ -39,5 +39,9 @@ If the compass fallback starts to show unreliable values, you can reset the cali ## Widget -The widget keeps the sensors alive and records some very basic statics when the app is not started. -This uses a lot of power so ensure to stop the app if you are not actively using it. +The widget keeps the sensors alive and records some very basic statistics when the app is not started. It shows as the app icon in the widget bar when the background task is active. +This uses a lot of power so ensure to stop the app if you are not actively using it. + +# Creator + +[halemmerich](https://github.com/halemmerich) diff --git a/apps/gpstrek/app.js b/apps/gpstrek/app.js index 091c407fb..0c3579d4b 100644 --- a/apps/gpstrek/app.js +++ b/apps/gpstrek/app.js @@ -6,8 +6,8 @@ if (showWidgets){ Bangle.loadWidgets(); } -let state = WIDGETS["gpstrek"].getState(); -WIDGETS["gpstrek"].start(); +let state = WIDGETS.gpstrek.getState(); +WIDGETS.gpstrek.start(false); function parseNumber(toParse){ if (toParse.includes(".")) return parseFloat(toParse); @@ -582,6 +582,18 @@ function showWaypointMenu(){ E.showMenu(menu); } +function showBackgroundMenu(){ + let menu = { + "" : { + "title" : "Background", + back : showMenu, + }, + "Start" : ()=>{ E.showPrompt("Start?").then((v)=>{ if (v) {WIDGETS.gpstrek.start(true); removeMenu();} else {E.showMenu(mainmenu);}});}, + "Stop" : ()=>{ E.showPrompt("Stop?").then((v)=>{ if (v) {WIDGETS.gpstrek.stop(true); removeMenu();} else {E.showMenu(mainmenu);}});}, + }; + E.showMenu(menu); +} + function showMenu(){ var mainmenu = { "" : { @@ -590,10 +602,9 @@ function showMenu(){ }, "Route" : showRouteMenu, "Waypoint" : showWaypointMenu, + "Background" : showBackgroundMenu, "Calibration": showCalibrationMenu, - "Start" : ()=>{ E.showPrompt("Start?").then((v)=>{ if (v) {state.active = true; removeMenu();} else {E.showMenu(mainmenu);}});}, - "Stop" : ()=>{ E.showPrompt("Stop?").then((v)=>{ if (v) {WIDGETS["gpstrek"].stop(); removeMenu();} else {E.showMenu(mainmenu);}});}, - "Reset" : ()=>{ E.showPrompt("Do Reset?").then((v)=>{ if (v) {WIDGETS["gpstrek"].resetState(); removeMenu();} else {E.showMenu(mainmenu);}});}, + "Reset" : ()=>{ E.showPrompt("Do Reset?").then((v)=>{ if (v) {WIDGETS.gpstrek.resetState(); removeMenu();} else {E.showMenu(mainmenu);}});}, "Slices" : { value : numberOfSlices, min:1,max:6,step:1, diff --git a/apps/gpstrek/metadata.json b/apps/gpstrek/metadata.json index 5168c870e..67f71566e 100644 --- a/apps/gpstrek/metadata.json +++ b/apps/gpstrek/metadata.json @@ -1,7 +1,7 @@ { "id": "gpstrek", "name": "GPS Trekking", - "version": "0.01", + "version": "0.02", "description": "Helper for tracking the status/progress during hiking. Do NOT depend on this for navigation!", "icon": "icon.png", "screenshots": [{"url":"screen1.png"},{"url":"screen2.png"},{"url":"screen3.png"},{"url":"screen4.png"}], @@ -13,5 +13,6 @@ {"name":"gpstrek.app.js","url":"app.js"}, {"name":"gpstrek.wid.js","url":"widget.js"}, {"name":"gpstrek.img","url":"app-icon.js","evaluate":true} - ] + ], + "data": [{"name":"gpstrek.state.json"}] } diff --git a/apps/gpstrek/widget.js b/apps/gpstrek/widget.js index bba1298d0..8d9831e06 100644 --- a/apps/gpstrek/widget.js +++ b/apps/gpstrek/widget.js @@ -1,6 +1,7 @@ (() => { const STORAGE=require('Storage'); let state = STORAGE.readJSON("gpstrek.state.json")||{}; +let bgChanged = false; function saveState(){ state.saved = Date.now(); @@ -8,7 +9,7 @@ function saveState(){ } E.on("kill",()=>{ - if (state.active){ + if (bgChanged){ saveState(); } }); @@ -72,7 +73,7 @@ function onPressure(e) { } } -function start(){ +function start(bg){ Bangle.on('GPS', onGPS); Bangle.on("HRM", onPulse); Bangle.on("mag", onMag); @@ -83,13 +84,20 @@ function start(){ Bangle.setHRMPower(1, "gpstrek"); Bangle.setCompassPower(1, "gpstrek"); Bangle.setBarometerPower(1, "gpstrek"); - state.active = true; + if (bg){ + if (!state.active) bgChanged = true; + state.active = true; + saveState(); + } Bangle.drawWidgets(); } -function stop(){ - state.active = false; - saveState(); +function stop(bg){ + if (bg){ + if (state.active) bgChanged = true; + state.active = false; + saveState(); + } Bangle.drawWidgets(); } @@ -107,7 +115,7 @@ if (state.saved && state.saved < Date.now() - 60000){ } if (state.active){ - start(); + start(false); } WIDGETS["gpstrek"]={ diff --git a/apps/iconlaunch/ChangeLog b/apps/iconlaunch/ChangeLog index fcd7c9194..858d13b80 100644 --- a/apps/iconlaunch/ChangeLog +++ b/apps/iconlaunch/ChangeLog @@ -2,3 +2,4 @@ 0.02: implemented "direct launch" and "one click exit" settings 0.03: Use default Bangle formatter for booleans 0.04: Support new fast app switching +0.05: Allow to directly eval apps instead of loading diff --git a/apps/iconlaunch/README.md b/apps/iconlaunch/README.md index 0d36fdeb4..0b67494ce 100644 --- a/apps/iconlaunch/README.md +++ b/apps/iconlaunch/README.md @@ -10,3 +10,7 @@ This launcher shows 9 apps per screen, making it much faster to navigate versus ## Technical note The app uses `E.showScroller`'s code in the app but not the function itself because `E.showScroller` doesn't report the position of a press to the select function. + +### Fastload option + +Fastload clears up the memory used by the launcher and directly evals the code of the app to load. This means if widgets are loaded (fullscreen option) it is possible that widgets stay loaded in apps not expecting that and the widgets may draw over the app. diff --git a/apps/iconlaunch/app.js b/apps/iconlaunch/app.js index 97f7f0ac1..fd58176db 100644 --- a/apps/iconlaunch/app.js +++ b/apps/iconlaunch/app.js @@ -1,31 +1,21 @@ { const s = require("Storage"); const settings = s.readJSON("launch.json", true) || { showClocks: true, fullscreen: false,direct:false,oneClickExit:false }; - - function returnToClock() { - Bangle.setUI(); - setTimeout(eval,0,s.read(".bootcde")); - } - - if( settings.oneClickExit) - setWatch(returnToClock, BTN1); - if (!settings.fullscreen) { - if (!global.WIDGETS) Bangle.loadWidgets(); + Bangle.loadWidgets(); Bangle.drawWidgets(); } - var apps = s .list(/\.info$/) .map((app) => { - var a = s.readJSON(app, 1); + var a = s.readJSON(app, 1); return ( a && { - name: a.name, - type: a.type, - icon: a.icon, - sortorder: a.sortorder, - src: a.src, + name: a.name, + type: a.type, + icon: a.icon, + sortorder: a.sortorder, + src: a.src, } ); }) @@ -38,34 +28,29 @@ ); apps.sort((a, b) => { var n = (0 | a.sortorder) - (0 | b.sortorder); - if (n) return n; // do sortorder first + if (n) return n; if (a.name < b.name) return -1; if (a.name > b.name) return 1; return 0; }); apps.forEach((app) => { - if (app.icon) app.icon = s.read(app.icon); // should just be a link to a memory area + if (app.icon) app.icon = s.read(app.icon); }); - let scroll = 0; let selectedItem = -1; const R = Bangle.appRect; - const iconSize = 48; - const appsN = Math.floor(R.w / iconSize); const whitespace = (R.w - appsN * iconSize) / (appsN + 1); - const itemSize = iconSize + whitespace; - - function drawItem(itemI, r) { + let drawItem = function(itemI, r) { g.clearRect(r.x, r.y, r.x + r.w - 1, r.y + r.h - 1); let x = 0; for (let i = itemI * appsN; i < appsN * (itemI + 1); i++) { if (!apps[i]) break; x += whitespace; if (!apps[i].icon) { - g.setFontAlign(0,0,0).setFont("12x20:2").drawString("?", x + r.x+iconSize/2, r.y + iconSize/2); + g.setFontAlign(0, 0, 0).setFont("12x20:2").drawString("?", x + r.x + iconSize / 2, r.y + iconSize / 2); } else { g.drawImage(apps[i].icon, x + r.x, r.y); } @@ -80,9 +65,8 @@ x += iconSize; } drawText(itemI); - } - - function drawItemAuto(i) { + }; + let drawItemAuto = function(i) { var y = idxToY(i); g.reset().setClipRect(R.x, y, R.x2, y + itemSize); drawItem(i, { @@ -92,11 +76,9 @@ h: itemSize }); g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1); - } - + }; let lastIsDown = false; - - function drawText(i) { + let drawText = function(i) { const selectedApp = apps[selectedItem]; const idy = (selectedItem - (selectedItem % 3)) / 3; if (!selectedApp || i != idy) return; @@ -111,14 +93,13 @@ appY + rect.height / 2 ); g.drawString(selectedApp.name, R.w / 2, appY); - } - - function selectItem(id, e) { + }; + let selectItem = function(id, e) { const iconN = E.clip(Math.floor((e.x - R.x) / itemSize), 0, appsN - 1); const appId = id * appsN + iconN; if( settings.direct && apps[appId]) { - load(apps[appId].src); + loadApp(apps[appId].src); return; } if (appId == selectedItem && apps[appId]) { @@ -126,42 +107,36 @@ if (!app.src || s.read(app.src) === undefined) { E.showMessage( /*LANG*/ "App Source\nNot found"); } else { - load(app.src); + loadApp(app.src); } } selectedItem = appId; drawItems(); - } - - function idxToY(i) { + }; + let idxToY = function(i) { return i * itemSize + R.y - (scroll & ~1); - } - - function YtoIdx(y) { + }; + let YtoIdx = function(y) { return Math.floor((y + (scroll & ~1) - R.y) / itemSize); - } - - function drawItems() { + }; + let drawItems = function() { g.reset().clearRect(R.x, R.y, R.x2, R.y2); g.setClipRect(R.x, R.y, R.x2, R.y2); var a = YtoIdx(R.y); var b = Math.min(YtoIdx(R.y2), 99); for (var i = a; i <= b; i++) drawItem(i, { - x: R.x, - y: idxToY(i), - w: R.w, - h: itemSize, - }); + x: R.x, + y: idxToY(i), + w: R.w, + h: itemSize, + }); g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1); - } - + }; drawItems(); g.flip(); - const itemsN = Math.ceil(apps.length / appsN); - - function onDrag(e){ + let onDrag = function(e) { g.setColor(g.theme.fg); g.setBgColor(g.theme.bg); let dy = e.dy; @@ -190,7 +165,6 @@ y += itemSize; } } else { - // d>0 g.setClipRect(R.x, R.y, R.x2, R.y + dy); let i = YtoIdx(R.y + dy); let y = idxToY(i); @@ -206,8 +180,7 @@ } } g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1); - } - + }; Bangle.setUI({ mode: "custom", drag: onDrag, @@ -217,4 +190,36 @@ selectItem(i, e); }, }); + const returnToClock = function() { + loadApp(".bootcde"); + }; + let watch; + let loadApp; + if (settings.fastload){ + loadApp = function(name) { + Bangle.setUI(); + if (watch) clearWatch(watch); + apps = []; + delete drawItemAuto; + delete drawText; + delete selectItem; + delete onDrag; + delete drawItems; + delete drawItem; + delete returnToClock; + delete idxToY; + delete YtoIdx; + delete settings; + setTimeout(eval, 0, s.read(name)); + return; + }; + } else { + loadApp = function(name) { + load(name); + } + } + + if (settings.oneClickExit) { + watch = setWatch(returnToClock, BTN1); + } } diff --git a/apps/iconlaunch/metadata.json b/apps/iconlaunch/metadata.json index f1c34cf3d..82d2e7578 100644 --- a/apps/iconlaunch/metadata.json +++ b/apps/iconlaunch/metadata.json @@ -2,7 +2,7 @@ "id": "iconlaunch", "name": "Icon Launcher", "shortName" : "Icon launcher", - "version": "0.04", + "version": "0.05", "icon": "app.png", "description": "A launcher inspired by smartphones, with an icon-only scrollable menu.", "tags": "tool,system,launcher", diff --git a/apps/iconlaunch/settings.js b/apps/iconlaunch/settings.js index bd1a4a597..449a1c096 100644 --- a/apps/iconlaunch/settings.js +++ b/apps/iconlaunch/settings.js @@ -28,6 +28,10 @@ /*LANG*/"One click exit": { value: settings.oneClickExit == true, onchange: (m) => { save("oneClickExit", m) } + }, + /*LANG*/"Fastload": { + value: settings.fastload == true, + onchange: (m) => { save("fastload", m) } } }; E.showMenu(appMenu); diff --git a/apps/primetime/README.md b/apps/primetime/README.md new file mode 100644 index 000000000..a07c19f52 --- /dev/null +++ b/apps/primetime/README.md @@ -0,0 +1,10 @@ +# App Name + +Watchface that displays time and the prime factors of the "military time" (i.e. 21:05 => 2105, shows prime factors of 2105 which are 5 & 421). Displays "Prime Time!" if prime. + +![image](https://user-images.githubusercontent.com/115424919/194777279-7f5e4d2a-f475-4099-beaf-38db5b460714.png) + + +## Creator + +Adapted from simplestclock by [Eve Bury](https://www.github.com/eveeeon) diff --git a/apps/primetime/app.png b/apps/primetime/app.png new file mode 100644 index 000000000..5024727fb Binary files /dev/null and b/apps/primetime/app.png differ diff --git a/apps/primetime/metadata.json b/apps/primetime/metadata.json new file mode 100644 index 000000000..d796d290c --- /dev/null +++ b/apps/primetime/metadata.json @@ -0,0 +1,15 @@ +{ "id": "primetime", + "name": "Prime Time Clock", + "version": "0.01", + "type": "clock", + "description": "A clock that tells you the primes of the time", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "tags": "clock", + "supports": ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"primetime.app.js","url":"primetime.js"}, + {"name":"primetime.img","url":"primetime-icon.js","evaluate":true} + ] +} diff --git a/apps/primetime/primetime-icon.js b/apps/primetime/primetime-icon.js new file mode 100644 index 000000000..57969a68b --- /dev/null +++ b/apps/primetime/primetime-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgVVABVADJMBBf4L/Bf4LMgtQgIHCitAqoHBoEv+EHwALBv/S//4BYO//svwELoP//X/+gLB2E93+Ah9B9f+//QBYMVvv3C4XvvwLDl/0q+AgsB998qt4F4XgHYIXB/1+6ALC//93/4F4I7CI4QLBAIMLoF/6ABBBYNVqgBBgprCAIKz0qkAooLHgP8gXvvALH/EL7e4BY+tz/+vovH3PR1++L9YL/BYdVABQ=")) diff --git a/apps/primetime/primetime.js b/apps/primetime/primetime.js new file mode 100644 index 000000000..bba63bc48 --- /dev/null +++ b/apps/primetime/primetime.js @@ -0,0 +1,89 @@ +const h = g.getHeight(); +const w = g.getWidth(); + + + +// creates a list of prime factors of n and outputs them as a string, if n is prime outputs "Prime Time!" +function primeFactors(n) { + const factors = []; + let divisor = 2; + + while (n >= 2) { + if (n % divisor == 0) { + factors.push(divisor); + n = n / divisor; + } else { + divisor++; + } + } + if (factors.length === 1) { + return "Prime Time!"; + } + else + return factors.toString(); +} + + +// converts time HR:MIN to integer HRMIN e.g. 15:35 => 1535 +function timeToInt(t) { + var arr = t.split(':'); + var intTime = parseInt(arr[0])*100+parseInt(arr[1]); + + return intTime; +} + + + +function draw() { + var date = new Date(); + var timeStr = require("locale").time(date,1); + var primeStr = primeFactors(timeToInt(timeStr)); + + g.reset(); + g.setColor(0,0,0); + g.fillRect(Bangle.appRect); + + g.setFont("6x8", w/30); + g.setFontAlign(0, 0); + g.setColor(100,100,100); + g.drawString(timeStr, w/2, h/2); + g.setFont("6x8", w/60); + g.drawString(primeStr, w/2, 3*h/4); + queueDraw(); +} + +// timeout used to update every minute +var drawTimeout; + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); +} + +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); + +g.clear(); + +// Show launcher when middle button pressed +// Bangle.setUI("clock"); +// use clockupdown as it tests for issue #1249 +Bangle.setUI("clockupdown", btn=> { + draw(); +}); + +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); +draw(); diff --git a/apps/primetime/screenshot.png b/apps/primetime/screenshot.png new file mode 100644 index 000000000..cb625a9b6 Binary files /dev/null and b/apps/primetime/screenshot.png differ diff --git a/apps/waypointer/ChangeLog b/apps/waypointer/ChangeLog index 292d77a99..ea86cbe0c 100644 --- a/apps/waypointer/ChangeLog +++ b/apps/waypointer/ChangeLog @@ -2,3 +2,4 @@ 0.02: Make Bangle.js 2 compatible 0.03: Silently use built in heading when no magnav calibration file is present 0.04: Move waypoints.json (and editor) to 'waypoints' app +0.05: Fix not displaying of wpindex = 0 diff --git a/apps/waypointer/app.js b/apps/waypointer/app.js index 9fd288c9a..fe3f73fc3 100644 --- a/apps/waypointer/app.js +++ b/apps/waypointer/app.js @@ -263,7 +263,7 @@ function nextwp(inc){ } function doselect(){ - if (selected && wpindex!=0 && waypoints[wpindex].lat===undefined && savedfix.fix) { + if (selected && wpindex>=0 && waypoints[wpindex].lat===undefined && savedfix.fix) { waypoints[wpindex] ={name:"@"+wp.name, lat:savedfix.lat, lon:savedfix.lon}; wp = waypoints[wpindex]; require("waypoints").save(waypoints); diff --git a/apps/waypointer/metadata.json b/apps/waypointer/metadata.json index 8b923c604..a55db8c0e 100644 --- a/apps/waypointer/metadata.json +++ b/apps/waypointer/metadata.json @@ -1,7 +1,7 @@ { "id": "waypointer", "name": "Way Pointer", - "version": "0.04", + "version": "0.05", "description": "Navigate to a waypoint using the GPS for bearing and compass to point way, uses the same waypoint interface as GPS Navigation", "icon": "waypointer.png", "tags": "tool,outdoors,gps", diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index 8bd23dd77..c7dbb0d03 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -78,7 +78,7 @@ const APP_KEYS = [ 'supports', 'allow_emulator', 'dependencies' ]; -const STORAGE_KEYS = ['name', 'url', 'content', 'evaluate', 'noOverwite', 'supports']; +const STORAGE_KEYS = ['name', 'url', 'content', 'evaluate', 'noOverwite', 'supports', 'noOverwrite']; const DATA_KEYS = ['name', 'wildcard', 'storageFile', 'url', 'content', 'evaluate']; const SUPPORTS_DEVICES = ["BANGLEJS","BANGLEJS2"]; // device IDs allowed for 'supports' const METADATA_TYPES = ["app","clock","widget","bootloader","RAM","launch","textinput","scheduler","notify","locale","settings","waypoints"]; // values allowed for "type" field diff --git a/core b/core index 6857957f5..764197500 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 6857957f5aedfd9d175ecbf8e49d08bb167b8128 +Subproject commit 76419750083a88ee7a569db3975ae1bdd6dc155a