diff --git a/README.md b/README.md index cd6edbd47..eaf8c6f4c 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,10 @@ about the app. // iframe, and it must post back an 'app' structure // like this one with 'storage','name' and 'id' set up + "interface": "interface.html", // if supplied, apps/interface.html is loaded in an + // iframe, and it may interact with the connected Bangle + // to retrieve information from it + "allow_emulator":true, // if 'app.js' will run in the emulator, set to true to // add an icon to allow your app to be tested diff --git a/apps.json b/apps.json index dedbb22a1..32d490768 100644 --- a/apps.json +++ b/apps.json @@ -173,7 +173,7 @@ "icon": "gpstime.png", "version":"0.01", "description": "Update the Bangle.js's clock based on the time from the GPS receiver", - "tags": "tool", + "tags": "tool,gps", "storage": [ {"name":"+gpstime","url":"gpstime.json"}, {"name":"-gpstime","url":"gpstime.js"}, @@ -185,7 +185,7 @@ "icon": "openlocation.png", "version":"0.01", "description": "Convert your current GPS location to a series of characters", - "tags": "tool,outdoors", + "tags": "tool,outdoors,gps", "storage": [ {"name":"+openloc","url":"openlocation.json"}, {"name":"-openloc","url":"openlocation.js","evaluate":true} @@ -196,13 +196,28 @@ "icon": "speedo.png", "version":"0.01", "description": "Show the current speed according to the GPS", - "tags": "tool,outdoors", + "tags": "tool,outdoors,gps", "storage": [ {"name":"+speedo","url":"speedo.json"}, {"name":"-speedo","url":"speedo.js"}, {"name":"*speedo","url":"speedo-icon.js","evaluate":true} ] }, + { "id": "gpsrec", + "name": "GPS Recorder", + "icon": "app.png", + "version":"0.01", + "interface": "interface.html", + "description": "Application that allows you to record a GPS track. Can run in background", + "tags": "tool,outdoors,gps", + "storage": [ + {"name":"+gpsrec","url":"app.json"}, + {"name":"-gpsrec","url":"app.js"}, + {"name":"@gpsrec","url":"app-settings.json","evaluate":true}, + {"name":"*gpsrec","url":"app-icon.js","evaluate":true}, + {"name":"=gpsrec","url":"widget.js"} + ] + }, { "id": "slevel", "name": "Spirit Level", "icon": "spiritlevel.png", diff --git a/apps/gpsrec/ChangeLog b/apps/gpsrec/ChangeLog new file mode 100644 index 000000000..efbc53fb0 --- /dev/null +++ b/apps/gpsrec/ChangeLog @@ -0,0 +1 @@ +0.00: New App! diff --git a/apps/gpsrec/app-icon.js b/apps/gpsrec/app-icon.js new file mode 100644 index 000000000..9ba966765 --- /dev/null +++ b/apps/gpsrec/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AF/W63P54XVCigACF4IACC6QsUF44yKC44sUF5QyEC5QuWF5fPC5Yv/F/3OAYgviwNdroqCwF6wHP1V6vQwKF61eiAABGAQqBFYOkAYOr62rwADBF63V1ZOCmgvCmgvB1Wk1QEB0ml6vVGYOAF65PBDQU6F4rvH6qYB0ovXDQN66vW1hgBmhnBF5AwBAgOlSQgvR5+lC4fPFpAvECASSFd6weBABR3HSQYvpSQQvsUILWBF9XVX4OkF9bvd0ocB5/O1XOR5er0oIDF62AJoPPAYIzBF5QAFF6QoBE4OrVgKACGYIvI6GI1gvXFYN60q/D52k5ySFFwc0iEQrxfXK4TvGSQoTCwQuBAAJhDF6GIxHQ6vVGgQAESQfOTwQvZnQWBmgXDF4qSC5+kGYOr62sR4U0R6WsI4eCF5AzETwYYBwWC6AvlX4gAIR553DR5Ivhd4OCFwYvpAAwv/F7wMBF6ouLF5APHF54sMF44SNF5IsPF4gUSGQQXVAH4A/AH4A/ADY")) diff --git a/apps/gpsrec/app-settings.json b/apps/gpsrec/app-settings.json new file mode 100644 index 000000000..7e1c8ee72 --- /dev/null +++ b/apps/gpsrec/app-settings.json @@ -0,0 +1,5 @@ +{ + "recording":false, + "file":0, + "period":1 +} diff --git a/apps/gpsrec/app.js b/apps/gpsrec/app.js new file mode 100644 index 000000000..890cf95bf --- /dev/null +++ b/apps/gpsrec/app.js @@ -0,0 +1,115 @@ +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +var settings = require("Storage").readJSON("@gpsrec")||{}; + +function getFN(n) { + return ".gpsrc"+n.toString(36); +} + +function updateSettings() { + require("Storage").write("@gpsrec", settings); + if (WIDGETS["gpsrec"]) + WIDGETS["gpsrec"].reload(); +} + +function showMainMenu() { + const mainmenu = { + '': { 'title': 'GPS Record' }, + 'RECORD': { + value: !!settings.recording, + format: v=>v?"On":"Off", + onchange: v => { + settings.recording = v; + updateSettings(); + } + }, + 'File #': { + value: settings.file|0, + min: 0, + max: 35, + step: 1, + onchange: v => { + settings.recording = false; + settings.file = v; + updateSettings(); + } + }, + 'Time Period': { + value: settings.period||1, + min: 1, + max: 60, + step: 1, + onchange: v => { + settings.recording = false; + settings.period = v; + updateSettings(); + } + }, + 'View Tracks': viewTracks, + '< Back': ()=>{load();} + }; + return E.showMenu(mainmenu); +} + +function viewTracks() { + const menu = { + '': { 'title': 'GPS Tracks' } + }; + var found = false; + for (var n=0;n<36;n++) { + var f = require("Storage").open(getFN(n),"r"); + if (f.readLine()!==undefined) { + menu["Track "+n] = viewTrack.bind(null,n); + found = true; + } + } + if (!found) + menu["No Tracks found"] = function(){}; + menu['< Back'] = showMainMenu; + return E.showMenu(menu); +} + +function viewTrack(n) { + const menu = { + '': { 'title': 'GPS Track '+n } + }; + var trackCount = 0; + var trackTime; + var f = require("Storage").open(getFN(n),"r"); + var l = f.readLine(); + if (l!==undefined) { + var c = l.split(","); + trackTime = new Date(0|c[0]); + } + while (l!==undefined) { + trackCount++; + // TODO: min/max/length of track? + l = f.readLine(); + } + if (trackTime) + menu[" "+trackTime.toISOString().substr(0,16).replace("T"," ")] = function(){}; + menu[trackCount+" records"] = function(){}; + // TODO: option to draw it? Just scan through, project using min/max + menu['Erase'] = function() { + E.showPrompt("Delete Track?").then(function(v) { + if (v) { + settings.recording = false; + updateSettings(); + var f = require("Storage").open(getFN(n),"r"); + f.erase(); + viewTracks(); + } else + viewTrack(n); + }); + }; + menu['< Back'] = viewTracks; + print(menu); + return E.showMenu(menu); +} + +showMainMenu(); + + +// f = require("Storage").open(".gpsrc"+n,"r"); +// f.readLine()... diff --git a/apps/gpsrec/app.json b/apps/gpsrec/app.json new file mode 100644 index 000000000..aa8416a77 --- /dev/null +++ b/apps/gpsrec/app.json @@ -0,0 +1,5 @@ +{ + "name":"GPS Recorder", + "icon":"*gpsrec", + "src":"-gpsrec" +} diff --git a/apps/gpsrec/app.png b/apps/gpsrec/app.png new file mode 100644 index 000000000..ab6d37c3b Binary files /dev/null and b/apps/gpsrec/app.png differ diff --git a/apps/gpsrec/interface.html b/apps/gpsrec/interface.html new file mode 100644 index 000000000..cf6b2c311 --- /dev/null +++ b/apps/gpsrec/interface.html @@ -0,0 +1,37 @@ + + + + + + +

Hello!

+ + + + diff --git a/apps/gpsrec/widget.js b/apps/gpsrec/widget.js new file mode 100644 index 000000000..84870a38e --- /dev/null +++ b/apps/gpsrec/widget.js @@ -0,0 +1,76 @@ +(() => { + // add the width + var xpos = WIDGETPOS.tl; + WIDGETPOS.tl += 24;/* the widget width plus some extra pixel to keep distance to others */; + var settings = {}; + var hasFix = false; + var fixToggle = false; // toggles once for each reading + var gpsTrack; // file for GPS track + var periodCtr = 0; + + // draw your widget at xpos + function draw() { + g.reset(); + g.setFont("4x6"); + g.setFontAlign(0,0); + g.clearRect(xpos,0,xpos+23,23); + + if (!settings.recording) { + g.setColor("#606060"); + } else { + g.setColor("#ff0000"); + if (hasFix) { + if (fixToggle) { + g.fillCircle(xpos+11,11,9); + g.setColor("#000000"); + } else + g.drawCircle(xpos+11,11,9); + } else { + g.setColor(fixToggle ? "#ff0000" : "#7f0000"); + g.drawString("NO",xpos+12,5); + g.drawString("FIX",xpos+12,19); + } + } + g.drawString("GPS",xpos+12,12); + } + + function onGPS(fix) { + hasFix = fix.fix; + fixToggle = !fixToggle; + draw(); + if (hasFix) { + periodCtr--; + if (periodCtr<=0) { + periodCtr = settings.period; + if (gpsTrack) gpsTrack.write([ + fix.time.getTime()|0, + fix.lat.toFixed(5), + fix.lon.toFixed(5), + fix.alt + ].join(",")+"\n"); + } + } + } + + // Called by the GPS app to reload settings and decide what's + function reload() { + settings = require("Storage").readJSON("@gpsrec")||{}; + settings.period = settings.period||1; + settings.file |= 0; + + Bangle.removeListener('GPS',onGPS); + if (settings.recording) { + Bangle.on('GPS',onGPS); + Bangle.setGPSPower(1); + var n = settings.file.toString(36); + gpsTrack = require("Storage").open(".gpsrc"+n,"a"); + } else { + Bangle.setGPSPower(0); + gpsTrack = undefined; + } + draw(); + } + reload(); + // add the widget + WIDGETS["gpsrec"]={draw:draw,reload:reload}; +})() diff --git a/index.js b/index.js index cb9352331..a4ec8799b 100644 --- a/index.js +++ b/index.js @@ -86,6 +86,8 @@ function showPrompt(title, text) { }); } function handleCustomApp(app) { + // Pops up an IFRAME that allows an app to be customised + if (!app.custom) throw new Error("App doesn't have custom HTML"); return new Promise((resolve,reject) => { var modal = htmlElement(`