diff --git a/apps/authentiwatch/interface.html b/apps/authentiwatch/interface.html index 7d567d34f..d7cd59f1a 100644 --- a/apps/authentiwatch/interface.html +++ b/apps/authentiwatch/interface.html @@ -12,8 +12,8 @@ body.select div.select,body.export div.export{display:block} body.select div.export,body.export div.select{display:none} body.select div#tokens,body.editing div#edit,body.scanning div#scan,body.showqr div#showqr,body.export div#tokens{display:block} #tokens th,#tokens td{padding:5px} -#tokens tr:nth-child(odd){background-color:#ccc} -#tokens tr:nth-child(even){background-color:#eee} +#tokens tr:nth-child(odd){background-color:#f1f1fc} +#tokens tr:nth-child(even){background-color:#fff} #qr-canvas{margin:auto;width:calc(100%-20px);max-width:400px} #advbtn,#scan,#tokenqr table{text-align:center} #edittoken tbody#adv{display:none} @@ -226,15 +226,18 @@ function editToken(id) { markup += selectMarkup('algorithm', otpAlgos, tokens[id].algorithm); markup += ''; markup += ''; - markup += ''; + markup += ''; markup += ''; - markup += ''; - markup += ''; + markup += ''; + markup += ' '; + markup += ''; + markup += ' '; if (tokens[id].isnew) { - markup += ''; + markup += ''; } else { - markup += ''; - markup += ''; + markup += ''; + markup += ' '; + markup += ''; } document.getElementById('edit').innerHTML = markup; document.body.className = 'editing'; @@ -304,9 +307,23 @@ function updateTokens() { return ''; }; const tokenButton = function(fn, id, label, dir) { - return ''; + return ''; }; - var markup = '
'; + var markup = ''; + markup += '
'; + markup += ''; + markup += ' '; + markup += ''; + markup += ' '; + markup += ''; + markup += ' '; + markup += ''; + markup += '
'; + markup += ''; + markup += ' '; + markup += ''; + markup += '
'; + markup += ''; /* any tokens marked new are cancelled new additions and must be removed */ @@ -331,15 +348,6 @@ function updateTokens() { markup += ''; } markup += '
'; markup += tokenSelect('all'); markup += 'TokenOrder
'; - markup += '
'; - markup += ''; - markup += ''; - markup += ''; - markup += ''; - markup += '
'; - markup += ''; - markup += ''; - markup += '
'; document.getElementById('tokens').innerHTML = markup; document.body.className = 'select'; } @@ -604,7 +612,7 @@ function qrBack() {
- +
@@ -613,7 +621,7 @@ function qrBack() {
- +
diff --git a/apps/calendar/ChangeLog b/apps/calendar/ChangeLog index beba4ed95..cc8bb6306 100644 --- a/apps/calendar/ChangeLog +++ b/apps/calendar/ChangeLog @@ -4,3 +4,4 @@ 0.04: Add setting to switch color schemes. On Bangle 2 non-dithering colors will be used by default. Use localized names for months and days of the week (Language app needed). 0.05: Update calendar weekend colors for start on Sunday 0.06: Use larger font for dates +0.07: Fix off-by-one-error on previous month diff --git a/apps/calendar/calendar.js b/apps/calendar/calendar.js index 62702e349..3f4315811 100644 --- a/apps/calendar/calendar.js +++ b/apps/calendar/calendar.js @@ -171,7 +171,7 @@ function drawCalendar(date) { let days = []; let nextMonthDay = 1; let thisMonthDay = 51; - let prevMonthDay = monthMaxDayMap[month > 0 ? month - 1 : 11] - dowNorm; + let prevMonthDay = monthMaxDayMap[month > 0 ? month - 1 : 11] - dowNorm + 1; for (let i = 0; i < colN * (rowN - 1) + 1; i++) { if (i < dowNorm) { days.push(prevMonthDay); diff --git a/apps/calendar/metadata.json b/apps/calendar/metadata.json index 5531c03c3..62d2513ae 100644 --- a/apps/calendar/metadata.json +++ b/apps/calendar/metadata.json @@ -1,7 +1,7 @@ { "id": "calendar", "name": "Calendar", - "version": "0.06", + "version": "0.07", "description": "Simple calendar", "icon": "calendar.png", "screenshots": [{"url":"screenshot_calendar.png"}], diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index e263227e5..91d2bb0bf 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -39,4 +39,4 @@ 0.24: Remove left-over debug statement 0.25: Fix widget memory usage issues if message received and watch repeatedly calls Bangle.drawWidgets (fix #1550) 0.26: Setting to auto-open music -0.27: Option to auto-unlock the watch when a new message arrives +0.27: Add 'mark all read' option to popup menu (fix #1624) diff --git a/apps/messages/app.js b/apps/messages/app.js index 403f9b5d8..655fc7122 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -302,6 +302,11 @@ function showMessageSettings(msg) { saveMessages(); checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); }, + /*LANG*/"Mark all read" : () => { + MESSAGES.forEach(msg => msg.new = false); + saveMessages(); + checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); + }, /*LANG*/"Delete all messages" : () => { E.showPrompt(/*LANG*/"Are you sure?", {title:/*LANG*/"Delete All Messages"}).then(isYes => { if (isYes) { diff --git a/apps/quicklaunch/ChangeLog b/apps/quicklaunch/ChangeLog new file mode 100644 index 000000000..ec66c5568 --- /dev/null +++ b/apps/quicklaunch/ChangeLog @@ -0,0 +1 @@ +0.01: Initial version diff --git a/apps/quicklaunch/app-icon.js b/apps/quicklaunch/app-icon.js new file mode 100644 index 000000000..14ae94823 --- /dev/null +++ b/apps/quicklaunch/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("kMigILIgPAAYMD/ADBwcGhkAwM5wcA/+2//Av/Rn/giFoyFggkUrFggEKlAkCiApCx+AAYNGoADBkU4AYMQj4DBvEICANkAoIPBgE2B4MAiMAH4MAwECAYNALYUgBIISCHYMYAoQWBAIMEgAYBAIMBwEDDQNgDwUf/4eBg4DCAA4")) diff --git a/apps/quicklaunch/app.js b/apps/quicklaunch/app.js new file mode 100644 index 000000000..f2b749e3e --- /dev/null +++ b/apps/quicklaunch/app.js @@ -0,0 +1,120 @@ +var settings = Object.assign(require("Storage").readJSON("quicklaunch.json", true) || {}); + +var apps = require("Storage").list(/\.info$/).map(app=>{var a=require("Storage").readJSON(app,1);return a&&{name:a.name,type:a.type,sortorder:a.sortorder,src:a.src};}).filter(app=>app && (app.type=="app" || app.type=="launch" || app.type=="clock" || !app.type)); + +apps.sort((a,b)=>{ + var n=(0|a.sortorder)-(0|b.sortorder); + if (n) return n; // do sortorder first + if (a.nameb.name) return 1; + return 0; +}); + +function save(key, value) { + settings[key] = value; + require("Storage").write("quicklaunch.json",settings); +} + +// Quick Launch menu +function showMainMenu() { + var mainmenu = { + "" : { "title" : "Quick Launch" }, + "< Back" : ()=>{load();} + }; + + //List all selected apps + mainmenu["Left: "+settings.leftapp.name] = function() { E.showMenu(leftmenu); }; + mainmenu["Right: "+settings.rightapp.name] = function() { E.showMenu(rightmenu); }; + mainmenu["Up: "+settings.upapp.name] = function() { E.showMenu(upmenu); }; + mainmenu["Down: "+settings.downapp.name] = function() { E.showMenu(downmenu); }; + mainmenu["Tap: "+settings.tapapp.name] = function() { E.showMenu(tapmenu); }; + + return E.showMenu(mainmenu); +} + +//Left swipe menu +var leftmenu = { + "" : { "title" : "Left Swipe" }, + "< Back" : showMainMenu +}; + +leftmenu["(none)"] = function() { + save("leftapp", {"name":"(none)"}); + showMainMenu(); +}; +apps.forEach((a)=>{ + leftmenu[a.name] = function() { + save("leftapp", a); + showMainMenu(); + }; +}); + +//Right swipe menu +var rightmenu = { + "" : { "title" : "Right Swipe" }, + "< Back" : showMainMenu +}; + +rightmenu["(none)"] = function() { + save("rightapp", {"name":"(none)"}); + showMainMenu(); +}; +apps.forEach((a)=>{ + rightmenu[a.name] = function() { + save("rightapp", a); + showMainMenu(); + }; +}); + +//Up swipe menu +var upmenu = { + "" : { "title" : "Up Swipe" }, + "< Back" : showMainMenu +}; + +upmenu["(none)"] = function() { + save("upapp", {"name":"(none)"}); + showMainMenu(); +}; +apps.forEach((a)=>{ + upmenu[a.name] = function() { + save("upapp", a); + showMainMenu(); + }; +}); + +//Down swipe menu +var downmenu = { + "" : { "title" : "Down Swipe" }, + "< Back" : showMainMenu +}; + +downmenu["(none)"] = function() { + save("downapp", {"name":"(none)"}); + showMainMenu(); +}; +apps.forEach((a)=>{ + downmenu[a.name] = function() { + save("downapp", a); + showMainMenu(); + }; +}); + +//Tap menu +var tapmenu = { + "" : { "title" : "Tap" }, + "< Back" : showMainMenu +}; + +tapmenu["(none)"] = function() { + save("tapapp", {"name":"(none)"}); + showMainMenu(); +}; +apps.forEach((a)=>{ + tapmenu[a.name] = function() { + save("tapapp", a); + showMainMenu(); + }; +}); + +showMainMenu(); diff --git a/apps/quicklaunch/app.png b/apps/quicklaunch/app.png new file mode 100644 index 000000000..3d1d0fdd2 Binary files /dev/null and b/apps/quicklaunch/app.png differ diff --git a/apps/quicklaunch/boot.js b/apps/quicklaunch/boot.js new file mode 100644 index 000000000..3670c4776 --- /dev/null +++ b/apps/quicklaunch/boot.js @@ -0,0 +1,67 @@ +(function() { + var settings = Object.assign(require("Storage").readJSON("quicklaunch.json", true) || {}); + + //list all sources + var apps = require("Storage").list(/\.info$/).map(app=>{var a=require("Storage").readJSON(app,1);return a&&{src:a.src};}); + + //populate empty app list + + if (!settings.leftapp) { + settings["leftapp"] = {"name":"(none)"}; + require("Storage").write("quicklaunch.json",settings); + } + if (!settings.rightapp) { + settings["rightapp"] = {"name":"(none)"}; + require("Storage").write("quicklaunch.json",settings); + } + if (!settings.upapp) { + settings["upapp"] = {"name":"(none)"}; + require("Storage").write("quicklaunch.json",settings); + } + if (!settings.downapp) { + settings["downapp"] = {"name":"(none)"}; + require("Storage").write("quicklaunch.json",settings); + } + if (!settings.tapapp) { + settings["tapapp"] = {"name":"(none)"}; + require("Storage").write("quicklaunch.json",settings); + } + + //activate on clock faces + var sui = Bangle.setUI; + Bangle.setUI = function(mode, cb) { + sui(mode,cb); + if(!mode) return; + if ("object"==typeof mode) mode = mode.mode; + if (!mode.startsWith("clock")) return; + + function tap() { + //tap, check if source exists, launch + if ((settings.tapapp.src) && apps.some(e => e.src === settings.tapapp.src)) load (settings.tapapp.src); + } + + let drag; + let e; + + Bangle.on("touch",tap); + Bangle.on("drag", e => { + if (!drag) { // start dragging + drag = {x: e.x, y: e.y}; + } else if (!e.b) { // released + const dx = e.x-drag.x, dy = e.y-drag.y; + drag = null; + //horizontal swipes, check if source exists, launch + if (Math.abs(dx)>Math.abs(dy)+10) { + if ((settings.leftapp.src) && apps.some(e => e.src === settings.leftapp.src) && dx<0) load(settings.leftapp.src); + if ((settings.rightapp.src) && apps.some(e => e.src === settings.rightapp.src) && dx>0) load(settings.rightapp.src); + } + //vertical swipes, check if source exists, launch + else if (Math.abs(dy)>Math.abs(dx)+10) { + if ((settings.upapp.src) && apps.some(e => e.src === settings.upapp.src) && dy<0) load(settings.upapp.src); + if ((settings.downapp.src) && apps.some(e => e.src === settings.downapp.src) && dy>0) load(settings.downapp.src); + } + } + }); + + }; +})(); diff --git a/apps/quicklaunch/metadata.json b/apps/quicklaunch/metadata.json new file mode 100644 index 000000000..6411d1a5f --- /dev/null +++ b/apps/quicklaunch/metadata.json @@ -0,0 +1,14 @@ +{ "id": "quicklaunch", + "name": "Quick Launch", + "icon": "app.png", + "version":"0.01", + "description": "Tap or swipe left/right/up/down on your clock face to launch up to five apps of your choice.", + "tags": "tools, system", + "supports": ["BANGLEJS2"], + "storage": [ + {"name":"quicklaunch.app.js","url":"app.js"}, + {"name":"quicklaunch.boot.js","url":"boot.js"}, + {"name":"quicklaunch.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"quicklaunch.json"}] +} diff --git a/apps/run/ChangeLog b/apps/run/ChangeLog index 46fdb7e7e..9f1a547b1 100644 --- a/apps/run/ChangeLog +++ b/apps/run/ChangeLog @@ -9,4 +9,5 @@ 0.08: Added support for notifications from exstats. Support all stats from exstats 0.09: Fix broken start/stop if recording not enabled (fix #1561) 0.10: Don't allow the same setting to be chosen for 2 boxes (fix #1578) -0.11: Notifications fixes \ No newline at end of file +0.11: Notifications fixes +0.12: Fix for recorder not stopping at end of run. Bug introduced in 0.11 \ No newline at end of file diff --git a/apps/run/app.js b/apps/run/app.js index fb8158e58..19dcd7e88 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -59,7 +59,7 @@ function onStartStop() { layout.render(); }) ); - } else if (!settings.record && WIDGETS["recorder"]) { + } else { prepPromises.push( WIDGETS["recorder"].setRecording(false) ); @@ -68,7 +68,7 @@ function onStartStop() { if (!prepPromises.length) // fix for Promise.all bug in 2v12 prepPromises.push(Promise.resolve()); - + Promise.all(prepPromises) .then(() => { if (running) { diff --git a/apps/run/metadata.json b/apps/run/metadata.json index 09e5a3bed..b1b5617be 100644 --- a/apps/run/metadata.json +++ b/apps/run/metadata.json @@ -1,6 +1,6 @@ { "id": "run", "name": "Run", - "version":"0.11", + "version":"0.12", "description": "Displays distance, time, steps, cadence, pace and more for runners.", "icon": "app.png", "tags": "run,running,fitness,outdoors,gps", diff --git a/apps/run/settings.js b/apps/run/settings.js index 6a7d169c4..240df9f07 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -91,7 +91,7 @@ ]; notificationsMenu[/*LANG*/"Dist Pattern"] = { value: Math.max(0,vibTimes.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.dist.notifications))), - min: 0, max: vibTimes.length, + min: 0, max: vibTimes.length - 1, format: v => vibPatterns[v]||/*LANG*/"Off", onchange: v => { settings.notify.dist.notifications = vibTimes[v]; @@ -101,7 +101,7 @@ } notificationsMenu[/*LANG*/"Step Pattern"] = { value: Math.max(0,vibTimes.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.step.notifications))), - min: 0, max: vibTimes.length, + min: 0, max: vibTimes.length - 1, format: v => vibPatterns[v]||/*LANG*/"Off", onchange: v => { settings.notify.step.notifications = vibTimes[v]; @@ -111,7 +111,7 @@ } notificationsMenu[/*LANG*/"Time Pattern"] = { value: Math.max(0,vibTimes.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.time.notifications))), - min: 0, max: vibTimes.length, + min: 0, max: vibTimes.length - 1, format: v => vibPatterns[v]||/*LANG*/"Off", onchange: v => { settings.notify.time.notifications = vibTimes[v]; diff --git a/apps/todolist/README.md b/apps/todolist/README.md index 27c7cfb63..0e1beb74a 100644 --- a/apps/todolist/README.md +++ b/apps/todolist/README.md @@ -2,39 +2,63 @@ Todo List ======== This is a simple Todo List application. +The content is loaded from a JSON file. +A task can be marked as completed or uncompleted. ![](screenshot2.png) -The content is loaded from a JSON file. -You can mark a task as completed. +Once installed, the list can be modified via the `Download data from app` icon in the [Bangle.js App Store](https://banglejs.com/apps/) (TodoList app). + +![](screenshot4.png) + JSON file content example: ```javascript [ { - name: "Pro", - children: [ + "name": "Pro", + "children": [ { - name: "Read doc", - done: true, - children: [], + "name": "Read doc", + "done": true, + "children": [] } - ], + ] }, { - name: "Pers", - children: [ + "name": "Pers", + "children": [ { - name: "Grocery", - children: [ - { name: "Milk", done: false, children: [] }, - { name: "Eggs", done: false, children: [] }, - { name: "Cheese", done: false, children: [] }, - ], + "name": "Grocery", + "children": [ + { + "name": "Milk", + "done": false, + "children": [] + }, + { + "name": "Eggs", + "done": false, + "children": [] + }, + { + "name": "Cheese", + "done": false, + "children": [] + } + ] }, - { name: "Workout", done: false, children: [] }, - { name: "Learn Rust", done: false, children: [] }, - ], - }, + { + "name": "Workout", + "done": false, + "children": [] + }, + { + "name": "Learn Rust", + "done": false, + "children": [] + } + ] + } ] ``` \ No newline at end of file diff --git a/apps/todolist/interface.html b/apps/todolist/interface.html new file mode 100644 index 000000000..5b9cb038e --- /dev/null +++ b/apps/todolist/interface.html @@ -0,0 +1,135 @@ + + + + + + + +
+ + + + + +

+
+    
+    
+  
+
diff --git a/apps/todolist/metadata.json b/apps/todolist/metadata.json
index 0833a86bd..a8eb6118b 100644
--- a/apps/todolist/metadata.json
+++ b/apps/todolist/metadata.json
@@ -10,6 +10,7 @@
   "tags": "tool,todo",
   "supports": ["BANGLEJS", "BANGLEJS2"],
   "readme": "README.md",
+  "interface": "interface.html",
   "storage": [
     { "name": "todolist.app.js", "url": "app.js" },
     { "name": "todolist.img", "url": "app-icon.js", "evaluate": true }
diff --git a/apps/todolist/screenshot4.png b/apps/todolist/screenshot4.png
new file mode 100644
index 000000000..43db1b0e6
Binary files /dev/null and b/apps/todolist/screenshot4.png differ
diff --git a/modules/exstats.js b/modules/exstats.js
index ec0a838a7..b22f3f5d3 100644
--- a/modules/exstats.js
+++ b/modules/exstats.js
@@ -135,7 +135,7 @@ Bangle.on("GPS", function(fix) {
   if (stats["dist"]) stats["dist"].emit("changed",stats["dist"]);
   var duration = Date.now() - state.startTime; // in ms
   state.avrSpeed = state.distance * 1000 / duration; // meters/sec
-  state.curSpeed = state.curSpeed*0.8 + fix.speed*0.2/3.6; // meters/sec
+  if (!isNaN(fix.speed)) state.curSpeed = state.curSpeed*0.8 + fix.speed*0.2/3.6; // meters/sec
   if (stats["pacea"]) stats["pacea"].emit("changed",stats["pacea"]);
   if (stats["pacec"]) stats["pacec"].emit("changed",stats["pacec"]);
   if (stats["speed"]) stats["speed"].emit("changed",stats["speed"]);