diff --git a/apps.json b/apps.json index 7985c6776..899eed03e 100644 --- a/apps.json +++ b/apps.json @@ -41,7 +41,7 @@ "name": "Default Launcher", "shortName":"Launcher", "icon": "app.png", - "version":"0.01", + "version":"0.02", "description": "This is needed by Bangle.js to display a menu allowing you to choose your own applications. You can replace this with a customised launcher.", "tags": "tool,system,launcher", "type":"launch", @@ -411,7 +411,7 @@ { "id": "swatch", "name": "Stopwatch", "icon": "stopwatch.png", - "version":"0.05", + "version":"0.06", "interface": "interface.html", "description": "Simple stopwatch with Lap Time logging to a JSON file", "tags": "health", @@ -1050,7 +1050,7 @@ "name": "Touch Launcher", "shortName":"Menu", "icon": "app.png", - "version":"0.05", + "version":"0.06", "description": "Touch enable left to right launcher.", "tags": "tool,system,launcher", "type":"launch", @@ -1123,20 +1123,35 @@ {"name":"openstmap.img","url":"app-icon.js","evaluate":true} ] }, - { "id": "activepedom", + { "id": "activepedom", "name": "Active Pedometer", "shortName":"Active Pedometer", "icon": "app.png", - "version":"0.01", + "version":"0.02", "description": "Pedometer that filters out arm movement and displays a step goal progress.", "tags": "outdoors,widget", "type":"widget", + "readme": "README.md", "storage": [ {"name":"activepedom.wid.js","url":"widget.js"}, {"name":"activepedom.settings.js","url":"settings.js"}, {"name":"activepedom.img","url":"app-icon.js","evaluate":true} ] }, + { "id": "chronowid", + "name": "Chrono Widget", + "shortName":"Chrono Widget", + "icon": "app.png", + "version":"0.01", + "description": "Chronometer (timer) which runs as widget.", + "tags": "tools,widget", + "readme": "README.md", + "storage": [ + {"name":"chronowid.wid.js","url":"widget.js"}, + {"name":"chronowid.app.js","url":"app.js"}, + {"name":"chronowid.img","url":"app-icon.js","evaluate":true} + ] + }, { "id": "tabata", "name": "Tabata", "shortName": "Tabata - Control High-Intensity Interval Training", @@ -1206,7 +1221,7 @@ "name": "Numerals Clock", "shortName": "Numerals Clock", "icon": "numerals.png", - "version":"0.02", + "version":"0.03", "description": "A simple big numerals clock", "tags": "numerals,clock", "type":"clock", @@ -1214,7 +1229,8 @@ "storage": [ {"name":"numerals.app.js","url":"numerals.app.js"}, {"name":"numerals.img","url":"numerals-icon.js","evaluate":true}, - {"name":"numerals.settings.js","url":"numerals.settings.js"} + {"name":"numerals.settings.js","url":"numerals.settings.js"}, + {"name":"numerals.json","url":"numerals-default.json","evaluate":true} ] }, { "id": "bledetect", diff --git a/apps/activepedom/ChangeLog b/apps/activepedom/ChangeLog index 4c21f3ace..fb0bc78e5 100644 --- a/apps/activepedom/ChangeLog +++ b/apps/activepedom/ChangeLog @@ -1 +1,2 @@ -0.01: New Widget! +0.01: New Widget! +0.02: Distance calculation and display \ No newline at end of file diff --git a/apps/activepedom/README.md b/apps/activepedom/README.md index 8a10727cd..055a91f56 100644 --- a/apps/activepedom/README.md +++ b/apps/activepedom/README.md @@ -1,4 +1,4 @@ -# Improved pedometer +# Active Pedometer Pedometer that filters out arm movement and displays a step goal progress. I changed the step counting algorithm completely. @@ -19,8 +19,9 @@ When you reach the step threshold, the steps needed to reach the threshold are c ## Features * Two line display +* Can display distance (in km) or steps in each line * Large number for good readability -* Small number with the exact steps counted +* Small number with the exact steps counted or more exact distance * Large number is displayed in green when status is 'active' * Progress bar for step goal * Counts steps only if they are reached in a certain time @@ -29,9 +30,23 @@ When you reach the step threshold, the steps needed to reach the threshold are c * Steps are saved to a file and read-in at start (to not lose step progress) * Settings can be changed in Settings - App/widget settings - Active Pedometer -## Development version +## Settings -* https://github.com/Purple-Tentacle/BangleAppsDev/tree/master/apps/pedometer +* Max time (ms): Maximum time between two steps in milliseconds, steps will not be counted if exceeded. Standard: 1100 +* Min time (ms): Minimum time between two steps in milliseconds, steps will not be counted if fallen below. Standard: 240 +* Step threshold: How many steps are needed to reach 'active' mode. If you do not reach the threshold in the 'Active Reset' time, the steps are not counted. Standard: 30 +* Act.Res. (ms): Active Reset. After how many miliseconds will the 'active mode' reset. You have to reach the step threshold in this time, otherwise the steps are not counted. Standard: 30000 +* Step sens.: Step Sensitivity. How sensitive should the sted detection be? This changes sensitivity in step detection in the firmware. Standard in firmware: 80 +* Step goal: This is your daily step goal. Standard: 10000 +* Step length: Length of one step in cm. Standard: 75 +* Line One: What to display in line one, steps or distance. Standard: steps +* Line Two: What to display in line two, steps or distance. Standard: distance + +## Releases + +* Offifical app loader: https://github.com/espruino/BangleApps/tree/master/apps/activepedom (https://banglejs.com/apps) +* Forked app loader: https://github.com/Purple-Tentacle/BangleApps/tree/master/apps/activepedom (https://purple-tentacle.github.io/BangleApps/#widget) +* Development: https://github.com/Purple-Tentacle/BangleAppsDev/tree/master/apps/pedometer ## Requests diff --git a/apps/activepedom/settings.js b/apps/activepedom/settings.js index 43764a164..94ae435d2 100644 --- a/apps/activepedom/settings.js +++ b/apps/activepedom/settings.js @@ -4,6 +4,7 @@ */ (function(back) { const SETTINGS_FILE = 'activepedom.settings.json'; + const LINES = ['Steps', 'Distance']; // initialize with default settings... let s = { @@ -13,6 +14,9 @@ 'intervalResetActive' : 30000, 'stepSensitivity' : 80, 'stepGoal' : 10000, + 'stepLength' : 75, + 'lineOne': LINES[0], + 'lineTwo': LINES[1], }; // ...and overwrite them with any saved values // This way saved values are preserved if a new version adds more settings @@ -27,7 +31,7 @@ return function (value) { s[key] = value; storage.write(SETTINGS_FILE, s); - WIDGETS["activepedom"].draw(); + //WIDGETS["activepedom"].draw(); }; } @@ -76,6 +80,33 @@ step: 1000, onchange: save('stepGoal'), }, + 'Step length (cm)': { + value: s.stepLength, + min: 1, + max: 150, + step: 1, + onchange: save('stepLength'), + }, + 'Line One': { + format: () => s.lineOne, + onchange: function () { + // cycles through options + const oldIndex = LINES.indexOf(s.lineOne) + const newIndex = (oldIndex + 1) % LINES.length + s.lineOne = LINES[newIndex] + save('lineOne')(s.lineOne) + }, + }, + 'Line Two': { + format: () => s.lineTwo, + onchange: function () { + // cycles through options + const oldIndex = LINES.indexOf(s.lineTwo) + const newIndex = (oldIndex + 1) % LINES.length + s.lineTwo = LINES[newIndex] + save('lineTwo')(s.lineTwo) + }, + }, }; E.showMenu(menu); }); \ No newline at end of file diff --git a/apps/activepedom/widget.js b/apps/activepedom/widget.js index 0c8b2438d..d569716ec 100644 --- a/apps/activepedom/widget.js +++ b/apps/activepedom/widget.js @@ -8,22 +8,16 @@ var active = 0; //x steps in y seconds achieved var stepGoalPercent = 0; //percentage of step goal var stepGoalBarLength = 0; //length og progress bar - var lastUpdate = new Date(); - var width = 45; + var lastUpdate = new Date(); //used to reset counted steps on new day + var width = 45; //width of widget - var stepsTooShort = 0; + //used for statistics and debugging + var stepsTooShort = 0; var stepsTooLong = 0; var stepsOutsideTime = 0; - //define default settings - const DEFAULTS = { - 'cMaxTime' : 1100, - 'cMinTime' : 240, - 'stepThreshold' : 30, - 'intervalResetActive' : 30000, - 'stepSensitivity' : 80, - 'stepGoal' : 10000, - }; + var distance = 0; //distance travelled + const SETTINGS_FILE = 'activepedom.settings.json'; const PEDOMFILE = "activepedom.steps.json"; @@ -32,10 +26,21 @@ function loadSettings() { settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {}; } + //return setting function setting(key) { - if (!settings) { loadSettings(); } - return (key in settings) ? settings[key] : DEFAULTS[key]; + //define default settings + const DEFAULTS = { + 'cMaxTime' : 1100, + 'cMinTime' : 240, + 'stepThreshold' : 30, + 'intervalResetActive' : 30000, + 'stepSensitivity' : 80, + 'stepGoal' : 10000, + 'stepLength' : 75, + }; + if (!settings) { loadSettings(); } + return (key in settings) ? settings[key] : DEFAULTS[key]; } function setStepSensitivity(s) { @@ -46,7 +51,7 @@ } //format number to make them shorter - function kFormatter(num) { + function kFormatterSteps(num) { if (num <= 999) return num; //smaller 1.000, return 600 as 600 if (num >= 1000 && num < 10000) { //between 1.000 and 10.000 num = Math.floor(num/100)*100; @@ -99,11 +104,12 @@ else { stepsOutsideTime++; } + settings = 0; //reset settings to save memory } function draw() { var height = 23; //width is deined globally - var stepsDisplayLarge = kFormatter(stepsCounted); + distance = (stepsCounted * setting('stepLength')) / 100 /1000 //distance in km //Check if same day let date = new Date(); @@ -121,10 +127,21 @@ if (active == 1) g.setColor(0x07E0); //green else g.setColor(0xFFFF); //white g.setFont("6x8", 2); - g.drawString(stepsDisplayLarge,this.x+1,this.y); //first line, big number + + if (setting('lineOne') == 'Steps') { + g.drawString(kFormatterSteps(stepsCounted),this.x+1,this.y); //first line, big number, steps + } + if (setting('lineOne') == 'Distance') { + g.drawString(distance.toFixed(2),this.x+1,this.y); //first line, big number, distance + } g.setFont("6x8", 1); g.setColor(0xFFFF); //white - g.drawString(stepsCounted,this.x+1,this.y+14); //second line, small number + if (setting('lineTwo') == 'Steps') { + g.drawString(stepsCounted,this.x+1,this.y+14); //second line, small number, steps + } + if (setting('lineTwo') == 'Distance') { + g.drawString(distance.toFixed(3) + "km",this.x+1,this.y+14); //second line, small number, distance + } //draw step goal bar stepGoalPercent = (stepsCounted / setting('stepGoal')) * 100; @@ -136,6 +153,8 @@ g.fillRect(this.x, this.y+height, this.x+1, this.y+height-1); //draw start of bar g.fillRect(this.x+width, this.y+height, this.x+width-1, this.y+height-1); //draw end of bar g.fillRect(this.x, this.y+height, this.x+stepGoalBarLength, this.y+height); // draw progress bar + + settings = 0; //reset settings to save memory } //This event is called just before the device shuts down for commands such as reset(), load(), save(), E.reboot() or Bangle.off() @@ -164,6 +183,7 @@ //Read data from file and set variables let pedomData = require("Storage").readJSON(PEDOMFILE,1); + if (pedomData) { if (pedomData.lastUpdate) lastUpdate = new Date(pedomData.lastUpdate); stepsCounted = pedomData.stepsToday|0; @@ -172,6 +192,8 @@ stepsOutsideTime = pedomData.stepsOutsideTime; } + pedomdata = 0; //reset pedomdata to save memory + setStepSensitivity(setting('stepSensitivity')); //set step sensitivity (80 is standard, 400 is muss less sensitive) //Add widget diff --git a/apps/chronowid/ChangeLog b/apps/chronowid/ChangeLog new file mode 100644 index 000000000..a6f342f01 --- /dev/null +++ b/apps/chronowid/ChangeLog @@ -0,0 +1 @@ +0.01: New widget and app! diff --git a/apps/chronowid/README.md b/apps/chronowid/README.md new file mode 100644 index 000000000..f31c24c7b --- /dev/null +++ b/apps/chronowid/README.md @@ -0,0 +1,35 @@ +# Chronometer Widget + +Chronometer (timer) that runs as a widget. +The advantage is, that you can still see your normal watchface and other widgets when the timer is running. +The widget is always active, but only shown when the timer is on. +Hours, minutes, seconds and timer status can be set with an app. + +## Screenshots + +TBD + +## Features + +* Using other apps does not interrupt the timer, no need to keep the widget open (BUT: there will be no buzz when the time is up, for that the widget has to be loaded) +* Target time is saved to a file and timer picks up again when widget is loaded again. + +## Settings + +There are no settings section in the settings app, timer can be set using an app. + +* Hours: Set the hours for the timer +* Minutes: Set the minutes for the timer +* Seconds: Set the seconds for the timer +* Timer on: Starts the timer and displays the widget when set to 'On'. You have to leave the app. The widget is always there, but only visible when timer is on. + + +## Releases + +* Offifical app loader: Not yet published. +* Forked app loader: https://github.com/Purple-Tentacle/BangleApps/tree/master/apps/chronowid (https://purple-tentacle.github.io/BangleApps/index.html#) +* Development: https://github.com/Purple-Tentacle/BangleAppsDev/tree/master/apps/chronowid + +## Requests + +If you have any feature requests, please contact me on the Espruino forum: http://forum.espruino.com/profiles/155005/ \ No newline at end of file diff --git a/apps/chronowid/app-icon.js b/apps/chronowid/app-icon.js new file mode 100644 index 000000000..db2010218 --- /dev/null +++ b/apps/chronowid/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwIFCn/8BYYFRABcD4AFFgIFCh/wgeAAoP//8HCYMDAoPD8EAg4FB8PwgEf+EP/H4HQOAgP8uEAvwfBv0ggBFCn4CB/EBwEfgEB+AFBh+AgfgAoI1BIoQJB4AHBAoXgg4uBAIIFCCYQFGh5rDJQJUBK4IFCNYIFVDoopDGoJiBHYYFKVYRZBWIYDBA4IFBNIQzBG4IbBToKkBAQKVFUIYICVoQUCXIQmCYoIsCaITqDAoLvDNYUAA=")) \ No newline at end of file diff --git a/apps/chronowid/app.js b/apps/chronowid/app.js new file mode 100644 index 000000000..48401a7bb --- /dev/null +++ b/apps/chronowid/app.js @@ -0,0 +1,91 @@ +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +const storage = require('Storage'); +const boolFormat = v => v ? "On" : "Off"; +let settingsChronowid; + +function updateSettings() { + var now = new Date(); + const goal = new Date(now.getFullYear(), now.getMonth(), now.getDate(), + now.getHours() + settingsChronowid.hours, now.getMinutes() + settingsChronowid.minutes, now.getSeconds() + settingsChronowid.seconds); + settingsChronowid.goal = goal.getTime(); + storage.writeJSON('chronowid.json', settingsChronowid); +} + +function resetSettings() { + settingsChronowid = { + hours : 0, + minutes : 0, + seconds : 0, + started : false, + counter : 0, + goal : 0, + }; + updateSettings(); +} + +settingsChronowid = storage.readJSON('chronowid.json',1); +if (!settingsChronowid) resetSettings(); + +E.on('kill', () => { + print("-KILL-"); + updateSettings(); +}); + +function showMenu() { + const timerMenu = { + '': { + 'title': 'Set timer', + 'predraw': function() { + timerMenu.hours.value = settingsChronowid.hours; + timerMenu.minutes.value = settingsChronowid.minutes; + timerMenu.seconds.value = settingsChronowid.seconds; + timerMenu.started.value = settingsChronowid.started; + } + }, + 'Hours': { + value: settingsChronowid.hours, + min: 0, + max: 24, + step: 1, + onchange: v => { + settingsChronowid.hours = v; + updateSettings(); + } + }, + 'Minutes': { + value: settingsChronowid.minutes, + min: 0, + max: 59, + step: 1, + onchange: v => { + settingsChronowid.minutes = v; + updateSettings(); + } + }, + 'Seconds': { + value: settingsChronowid.seconds, + min: 0, + max: 59, + step: 1, + onchange: v => { + settingsChronowid.seconds = v; + updateSettings(); + } + }, + 'Timer on': { + value: settingsChronowid.started, + format: boolFormat, + onchange: v => { + settingsChronowid.started = v; + updateSettings(); + } + }, + }; + timerMenu['-Exit-'] = ()=>{load();}; + return E.showMenu(timerMenu); +} + +showMenu(); diff --git a/apps/chronowid/app.png b/apps/chronowid/app.png new file mode 100644 index 000000000..5ac7a480c Binary files /dev/null and b/apps/chronowid/app.png differ diff --git a/apps/chronowid/widget.js b/apps/chronowid/widget.js new file mode 100644 index 000000000..708bc6345 --- /dev/null +++ b/apps/chronowid/widget.js @@ -0,0 +1,93 @@ +(() => { + const storage = require('Storage'); + settingsChronowid = storage.readJSON("chronowid.json",1)||{}; //read settingsChronowid from file + var height = 23; + var width = 58; + var interval = 0; //used for the 1 second interval timer + var now = new Date(); + + var time = 0; + var diff = settingsChronowid.goal - now; + + //Convert ms to time + function getTime(t) { + var milliseconds = parseInt((t % 1000) / 100), + seconds = Math.floor((t / 1000) % 60), + minutes = Math.floor((t / (1000 * 60)) % 60), + hours = Math.floor((t / (1000 * 60 * 60)) % 24); + + hours = (hours < 10) ? "0" + hours : hours; + minutes = (minutes < 10) ? "0" + minutes : minutes; + seconds = (seconds < 10) ? "0" + seconds : seconds; + + return hours + ":" + minutes + ":" + seconds; + } + + function printDebug() { + print ("Nowtime: " + getTime(now)); + print ("Now: " + now); + print ("Goaltime: " + getTime(settingsChronowid.goal)); + print ("Goal: " + settingsChronowid.goal); + print("Difftime: " + getTime(diff)); + print("Diff: " + diff); + print ("Started: " + settingsChronowid.started); + print ("----"); + } + + //counts down, calculates and displays + function countDown() { + //printDebug(); + now = new Date(); + diff = settingsChronowid.goal - now; //calculate difference + WIDGETS["chronowid"].draw(); + //time is up + if (settingsChronowid.started && diff <= 0) { + Bangle.buzz(1500); + //write timer off to file + settingsChronowid.started = false; + storage.writeJSON('chronowid.json', settingsChronowid); + clearInterval(interval); //stop interval + //printDebug(); + } + } + + // draw your widget + function draw() { + if (!settingsChronowid.started) { + width = 0; + return; //do not draw anything if timer is not started + } + g.reset(); + if (diff >= 0) { + if (diff < 600000) { //less than 1 hour left + width = 58; + g.clearRect(this.x,this.y,this.x+width,this.y+height); + g.setFont("6x8", 2); + g.drawString(getTime(diff).substring(3), this.x+1, this.y+5); //remove hour part 00:00:00 -> 00:00 + } + if (diff >= 600000) { //one hour or more left + width = 48; + g.clearRect(this.x,this.y,this.x+width,this.y+height); + g.setFont("6x8", 1); + g.drawString(getTime(diff), this.x+1, this.y+((height/2)-4)); //display hour 00:00:00 + } + } + else { + width = 58; + g.clearRect(this.x,this.y,this.x+width,this.y+height); + g.setFont("6x8", 2); + g.drawString("END", this.x+15, this.y+5); + } + } + + if (settingsChronowid.started) interval = setInterval(countDown, 1000); //start countdown each second + + // add the widget + WIDGETS["chronowid"]={area:"bl",width:width,draw:draw,reload:function() { + reload(); + Bangle.drawWidgets(); // relayout all widgets + }}; + + //printDebug(); + countDown(); +})(); \ No newline at end of file diff --git a/apps/launch/ChangeLog b/apps/launch/ChangeLog new file mode 100644 index 000000000..9e4a1eaf3 --- /dev/null +++ b/apps/launch/ChangeLog @@ -0,0 +1,2 @@ +0.01: New App! +0.02: Only store relevant app data (saves RAM when many apps) diff --git a/apps/launch/app.js b/apps/launch/app.js index 682122f82..a256b6909 100644 --- a/apps/launch/app.js +++ b/apps/launch/app.js @@ -1,5 +1,5 @@ var s = require("Storage"); -var apps = s.list(/\.info$/).map(app=>s.readJSON(app,1)||{name:"DEAD: "+app.substr(1)}).filter(app=>app.type=="app" || app.type=="clock" || !app.type); +var apps = s.list(/\.info$/).map(app=>{var a=s.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src}}).filter(app=>app && (app.type=="app" || app.type=="clock" || !app.type)); apps.sort((a,b)=>{ var n=(0|a.sortorder)-(0|b.sortorder); if (n) return n; // do sortorder first diff --git a/apps/locale/locales.js b/apps/locale/locales.js index ebf28e53d..508c92015 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -220,7 +220,7 @@ var locales = { int_curr_symbol: "ILS", speed: "kmh", distance: { 0: "m", 1: "km" }, - temperature: "°F", + temperature: "°C", ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, datePattern: { 0: "%A, %B %d, %Y", "1": "%d/%m/%Y" }, // Sunday, 1 March 2020 // 01/03/2020 diff --git a/apps/numerals/ChangeLog b/apps/numerals/ChangeLog index a8396e26b..ec465a83f 100644 --- a/apps/numerals/ChangeLog +++ b/apps/numerals/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Use BTN2 for settings menu like other clocks +0.03: maximize numerals, make menu button configurable, change icon to mac palette, add default settings file, respect 12hour setting \ No newline at end of file diff --git a/apps/numerals/README.md b/apps/numerals/README.md index 01d784ef8..52e84c76d 100644 --- a/apps/numerals/README.md +++ b/apps/numerals/README.md @@ -5,13 +5,16 @@ Settings can be accessed through the app/widget settings menu of the Bangle.js ## Settings available -### color: +### Color: * rnd - shows numerals in different color combinations every time the watches wakes * r/g - red/green * y/w - yellow/white * o/c - orange/cyan * b/y - blue/yellow'ish -### draw mode +### Draw mode * fill - fill numerals * frame - only shows outline of numerals + +### Menu button +* choose button to start launcher menu with \ No newline at end of file diff --git a/apps/numerals/numerals-default.json b/apps/numerals/numerals-default.json new file mode 100644 index 000000000..aa6a25047 --- /dev/null +++ b/apps/numerals/numerals-default.json @@ -0,0 +1,5 @@ +{ + color:0, + drawMode:"fill", + menuButton:22 +} \ No newline at end of file diff --git a/apps/numerals/numerals-icon.js b/apps/numerals/numerals-icon.js index 7e471fb0d..7ef609874 100644 --- a/apps/numerals/numerals-icon.js +++ b/apps/numerals/numerals-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwwhC/ABMBzIADyAJIAAkQBoMZBIoXCBIwADyIkIGAIuKGAQkIBJIwEEKQANC/4XWR58RiIHFWpAXFe4QRFcpAXFewQRFcxAXEFwQwGA4QXKiAXDGAgX/C/4X/C/4X/C7uQCwcBBwYXNBwYuEC54wCFwgXPzMRiIHFC54AHC/4XiCAoXRhIHDyK3GAAwOBJA0QG45VGC4YwCD4YwKFwgABcgIfEAwIAHBwgA/AAgA==")) \ No newline at end of file +require("heatshrink").decompress(atob("mEwwhC/ABXdAAfQBJAAEBgUNBJ4mGBKAmFEhAuLEwQhSABoX/C6yPPYw61IB4r3DHxoIFCwQIHC5YuDCIo3HC4oWEBI4X/C/4X/C/4X/C7XQC4gOEC5gwEBA4XLGAYOFC5oPCA44XNAA4X/C8SAGC6q4CCxb4EG5guICAgfIFxQA/ADg")) \ No newline at end of file diff --git a/apps/numerals/numerals.app.js b/apps/numerals/numerals.app.js index fbfe5b9ed..b24e8bc5e 100644 --- a/apps/numerals/numerals.app.js +++ b/apps/numerals/numerals.app.js @@ -7,57 +7,59 @@ */ var numerals = { - 0:[[9,1,82,1,90,9,90,82,82,90,9,90,1,82,1,9,9,1],[30,21,61,21,69,29,69,61,61,69,30,69,22,61,22,29,30,21]], - 1:[[59,1,82,1,90,9,90,82,82,90,73,90,65,82,65,27,59,27,51,19,51,9,59,1]], - 2:[[9,1,82,1,90,9,90,47,82,55,21,55,21,64,82,64,90,72,90,82,82,90,9,90,1,82,1,43,9,35,70,35,70,25,9,25,1,17,1,9,9,1]], - 3:[[9,1,82,1,90,9,90,82,82,90,9,90,1,82,1,74,9,66,70,66,70,57,9,57,1,49,1,41,9,33,70,33,70,25,9,25,1,17,1,9,9,1]], - 4:[[9,1,14,1,22,9,22,34,69,34,69,9,77,1,82,1,90,9,90,82,82,90,78,90,70,82,70,55,9,55,1,47,1,9,9,1]], - 5:[[9,1,82,1,90,9,90,17,82,25,21,25,21,35,82,35,90,43,90,82,82,90,9,90,1,82,1,72,9,64,71,64,71,55,9,55,1,47,1,9,9,1]], - 6:[[9,1,82,1,90,9,90,14,82,22,22,22,22,36,82,36,90,44,90,82,82,90,9,90,1,82,1,9,9,1],[22,55,69,55,69,69,22,69,22,55]], - 7:[[9,1,82,1,90,9,90,15,15,90,9,90,1,82,1,76,54,23,9,23,1,15,1,9,9,1]], - 8:[[9,1,82,1,90,9,90,82,82,90,9,90,1,82,1,9,9,1],[22,22,69,22,69,36,22,36,22,22],[22,55,69,55,69,69,22,69,22,55]], - 9:[[9,1,82,1,90,9,90,82,82,90,9,90,1,82,1,77,9,69,69,69,69,55,9,55,1,47,1,9,9,1],[22,22,69,22,69,36,22,36,22,22]], + 0:[[9,1,82,1,90,9,90,92,82,100,9,100,1,92,1,9],[30,25,61,25,69,33,69,67,61,75,30,75,22,67,22,33]], + 1:[[59,1,82,1,90,9,90,92,82,100,73,100,65,92,65,27,59,27,51,19,51,9]], + 2:[[9,1,82,1,90,9,90,53,82,61,21,61,21,74,82,74,90,82,90,92,82,100,9,100,1,92,1,48,9,40,70,40,70,27,9,27,1,19,1,9]], + 3:[[9,1,82,1,90,9,90,92,82,100,9,100,1,92,1,82,9,74,70,74,70,61,9,61,1,53,1,48,9,40,70,40,70,27,9,27,1,19,1,9]], + 4:[[9,1,14,1,22,9,22,36,69,36,69,9,77,1,82,1,90,9,90,92,82,100,78,100,70,92,70,61,9,61,1,53,1,9]], + 5:[[9,1,82,1,90,9,90,19,82,27,21,27,21,40,82,40,90,48,90,92,82,100,9,100,1,92,1,82,9,74,71,74,71,61,9,61,1,53,1,9]], + 6:[[9,1,82,1,90,9,90,19,82,27,22,27,22,40,82,40,90,48,90,92,82,100,9,100,1,92,1,9],[22,60,69,60,69,74,22,74]], + 7:[[9,1,82,1,90,9,90,15,20,98,9,98,1,90,1,86,56,22,9,22,1,14,1,9]], + 8:[[9,1,82,1,90,9,90,92,82,100,9,100,1,92,1,9],[22,27,69,27,69,43,22,43],[22,58,69,58,69,74,22,74]], + 9:[[9,1,82,1,90,9,90,92,82,100,9,100,1,92,1,82,9,74,69,74,69,61,9,61,1,53,1,9],[22,27,69,27,69,41,22,41]], }; +var _12hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]||false; var _hCol = ["#ff5555","#ffff00","#FF9901","#2F00FF"]; var _mCol = ["#55ff55","#ffffff","#00EFEF","#FFBF00"]; var _rCol = 0; var interval = 0; const REFRESH_RATE = 10E3; -function translate(tx, ty, p) { +function translate(tx, ty, p){ return p.map((x, i)=> x+((i%2)?ty:tx)); } function fill(poly){ - return g.fillPoly(poly); + return g.fillPoly(poly,true); } function frame(poly){ - return g.drawPoly(poly); + return g.drawPoly(poly,true); } let settings = require('Storage').readJSON('numerals.json',1); if (!settings) { settings = { - color: 0, - drawMode: "fill" + color:0, + drawMode:"fill", + menuButton:24 }; } function drawNum(num,col,x,y,func){ g.setColor(col); - let tx = x*100+35; - let ty = y*100+35; + let tx = x*100+25; + let ty = y*104+32; for (let i=0;i0) g.setColor((func==fill)?"#000000":col); - func(translate(tx, ty,numerals[num][i])); + func(translate(tx,ty,numerals[num][i])); } } function draw(drawMode){ let d = new Date(); - let h1 = Math.floor(d.getHours()/10); - let h2 = d.getHours()%10; + let h1 = Math.floor((_12hour?d.getHours()%12:d.getHours())/10); + let h2 = (_12hour?d.getHours()%12:d.getHours())%10; let m1 = Math.floor(d.getMinutes()/10); let m2 = d.getMinutes()%10; g.clearRect(0,24,240,240); @@ -70,7 +72,7 @@ function draw(drawMode){ Bangle.setLCDMode(); clearWatch(); -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +setWatch(Bangle.showLauncher, settings.menuButton, {repeat:false,edge:"falling"}); g.clear(); clearInterval(); @@ -78,8 +80,8 @@ if (settings.color>0) _rCol=settings.color-1; interval=setInterval(draw, REFRESH_RATE, settings.drawMode); draw(settings.drawMode); -Bangle.on('lcdPower', function(on) { - if (on) { +Bangle.on('lcdPower', function(on){ + if (on){ if (settings.color==0) _rCol = Math.floor(Math.random()*_hCol.length); draw(settings.drawMode); interval=setInterval(draw, REFRESH_RATE, settings.drawMode); @@ -90,4 +92,4 @@ Bangle.on('lcdPower', function(on) { }); Bangle.loadWidgets(); -Bangle.drawWidgets(); +Bangle.drawWidgets(); \ No newline at end of file diff --git a/apps/numerals/numerals.settings.js b/apps/numerals/numerals.settings.js index f9c417da6..2d388525c 100644 --- a/apps/numerals/numerals.settings.js +++ b/apps/numerals/numerals.settings.js @@ -4,15 +4,17 @@ }; function resetSettings() { numeralsSettings = { - color: 0, - drawMode: "fill" + color:0, + drawMode:"fill", + menuButton:22 }; updateSettings(); } let numeralsSettings = storage.readJSON('numerals.json',1); if (!numeralsSettings) resetSettings(); let dm = ["fill","frame"]; - let col = ["rnd","r/g","y/w","o/c","b/y"] + let col = ["rnd","r/g","y/w","o/c","b/y"]; + let btn = [[24,"BTN1"],[22,"BTN2"],[23,"BTN3"],[11,"BTN4"],[16,"BTN5"]]; var menu={ "" : { "title":"Numerals"}, "Colors": { @@ -27,6 +29,12 @@ format: v=>dm[v], onchange: v=> { numeralsSettings.drawMode=dm[v]; updateSettings();} }, + "Menu button": { + value: 1|btn[numeralsSettings.menuButton], + min:0,max:4, + format: v=>btn[v][1], + onchange: v=> { numeralsSettings.menuButton=btn[v][0]; updateSettings();} + }, "< back": back }; E.showMenu(menu); diff --git a/apps/swatch/ChangeLog b/apps/swatch/ChangeLog index 3246eeced..9a037fa41 100644 --- a/apps/swatch/ChangeLog +++ b/apps/swatch/ChangeLog @@ -5,3 +5,4 @@ Fixed bug from 0.01 where BN1 (reset) could clear the lap log when timer is running 0.04: Changed save file filename, add interface.html to allow laps to be loaded 0.05: Added widgets +0.06: Added total running time, moved lap time to smaller display, total run time now appends as first entry in array, saving now saves last lap as well diff --git a/apps/swatch/interface.html b/apps/swatch/interface.html index 928c5fe39..45391fb6e 100644 --- a/apps/swatch/interface.html +++ b/apps/swatch/interface.html @@ -17,11 +17,12 @@ function getLapTimes() {
\n`; lapData.forEach((lap,lapIndex) => { lap.date = lap.n.substr(7,16).replace("_"," "); + lap.elapsed = lap.d.shift(); // remove first item html += `
${lap.date}
-
${lap.d.length} Laps
+
${lap.d.length} Laps, total time ${lap.elapsed}
diff --git a/apps/swatch/stopwatch.js b/apps/swatch/stopwatch.js index 6f8ad9e34..659f0606d 100644 --- a/apps/swatch/stopwatch.js +++ b/apps/swatch/stopwatch.js @@ -1,8 +1,11 @@ +var tTotal = Date.now(); var tStart = Date.now(); var tCurrent = Date.now(); var started = false; -var timeY = 60; +var timeY = 45; var hsXPos = 0; +var TtimeY = 75; +var ThsXPos = 0; var lapTimes = []; var displayInterval; @@ -12,6 +15,7 @@ function timeToText(t) { var hs = Math.floor(t/10)%100; return mins+":"+("0"+secs).substr(-2)+"."+("0"+hs).substr(-2); } + function updateLabels() { g.reset(1); g.clearRect(0,23,g.getWidth()-1,g.getHeight()-24); @@ -23,36 +27,54 @@ function updateLabels() { g.setFont("6x8",1); g.setFontAlign(-1,-1); for (var i in lapTimes) { - if (i<16) - {g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),35,timeY + 30 + i*8);} - else if (i<32) - {g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),125,timeY + 30 + (i-16)*8);} + if (i<15) + {g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),35,timeY + 40 + i*8);} + else if (i<30) + {g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),125,timeY + 40 + (i-15)*8);} } drawsecs(); } + function drawsecs() { var t = tCurrent-tStart; - g.reset(1); - g.setFont("Vector",48); - g.setFontAlign(0,0); + var Tt = tCurrent-tTotal; var secs = Math.floor(t/1000)%60; var mins = Math.floor(t/60000); var txt = mins+":"+("0"+secs).substr(-2); + var Tsecs = Math.floor(Tt/1000)%60; + var Tmins = Math.floor(Tt/60000); + var Ttxt = Tmins+":"+("0"+Tsecs).substr(-2); var x = 100; - g.clearRect(0,timeY-26,200,timeY+26); - g.drawString(txt,x,timeY); + var Tx = 125; + g.reset(1); + g.setFont("Vector",38); + g.setFontAlign(0,0); + g.clearRect(0,timeY-21,200,timeY+21); + g.drawString(Ttxt,x,timeY); hsXPos = 5+x+g.stringWidth(txt)/2; + g.setFont("6x8",2); + g.clearRect(0,TtimeY-7,200,TtimeY+7); + g.drawString(txt,Tx,TtimeY); + ThsXPos = 5+Tx+g.stringWidth(Ttxt)/2; drawms(); } + function drawms() { var t = tCurrent-tStart; var hs = Math.floor(t/10)%100; + var Tt = tCurrent-tTotal; + var Ths = Math.floor(Tt/10)%100; g.setFontAlign(-1,0); g.setFont("6x8",2); g.clearRect(hsXPos,timeY,220,timeY+20); - g.drawString("."+("0"+hs).substr(-2),hsXPos,timeY+10); + g.drawString("."+("0"+Ths).substr(-2),hsXPos-5,timeY+14); + g.setFont("6x8",1); + g.clearRect(ThsXPos,TtimeY,220,TtimeY+5); + g.drawString("."+("0"+hs).substr(-2),ThsXPos-5,TtimeY+3); } + function getLapTimesArray() { + lapTimes.push(tCurrent-tTotal); return lapTimes.map(timeToText).reverse(); } @@ -61,7 +83,8 @@ setWatch(function() { // Start/stop Bangle.beep(); if (started) tStart = Date.now()+tStart-tCurrent; - tCurrent = Date.now(); + tTotal = Date.now()+tTotal-tCurrent; + tCurrent = Date.now(); if (displayInterval) { clearInterval(displayInterval); displayInterval = undefined; @@ -77,29 +100,33 @@ setWatch(function() { // Start/stop drawms(); }, 20); }, BTN2, {repeat:true}); + setWatch(function() { // Lap Bangle.beep(); if (started) { tCurrent = Date.now(); lapTimes.unshift(tCurrent-tStart); } - tStart = tCurrent; if (!started) { // save - var timenow= Date(); var filename = "swatch-"+(new Date()).toISOString().substr(0,16).replace("T","_")+".json"; + if (tCurrent!=tStart) + lapTimes.unshift(tCurrent-tStart); // this maxes out the 28 char maximum require("Storage").writeJSON(filename, getLapTimesArray()); + tStart = tCurrent = tTotal = Date.now(); + lapTimes = []; E.showMessage("Laps Saved","Stopwatch"); setTimeout(updateLabels, 1000); } else { + tStart = tCurrent; updateLabels(); } }, BTN1, {repeat:true}); setWatch(function() { // Reset if (!started) { - Bangle.beep(); - tStart = tCurrent = Date.now(); - lapTimes = []; + Bangle.beep(); + tStart = tCurrent = tTotal = Date.now(); + lapTimes = []; } updateLabels(); }, BTN3, {repeat:true}); diff --git a/apps/toucher/ChangeLog b/apps/toucher/ChangeLog index a2a709ee3..0c97d9e13 100644 --- a/apps/toucher/ChangeLog +++ b/apps/toucher/ChangeLog @@ -2,4 +2,5 @@ 0.02: Add swipe support and doucle tap to run application 0.03: Close launcher when lcd turn off 0.04: Complete rewrite to add animation and loop ( issue #210 ) -0.05: Improve perf \ No newline at end of file +0.05: Improve perf +0.06: Only store relevant app data (saves RAM when many apps) diff --git a/apps/toucher/app.js b/apps/toucher/app.js index b67e5b26c..cf7d5333b 100644 --- a/apps/toucher/app.js +++ b/apps/toucher/app.js @@ -5,8 +5,8 @@ g.flip(); const Storage = require("Storage"); function getApps(){ - return Storage.list(/\.info$/).filter(app => app.endsWith('.info')).map(app => Storage.readJSON(app,1) || { name: "DEAD: "+app.substr(1) }) - .filter(app=>app.type=="app" || app.type=="clock" || !app.type) + return Storage.list(/\.info$/).map(app=>{var a=Storage.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src,version:a.version}}) + .filter(app=>app && (app.type=="app" || app.type=="clock" || !app.type)) .sort((a,b)=>{ var n=(0|a.sortorder)-(0|b.sortorder); if (n) return n; // do sortorder first @@ -19,7 +19,7 @@ function getApps(){ const HEIGHT = g.getHeight(); const WIDTH = g.getWidth(); const HALF = WIDTH/2; -const ANIMATION_FRAME = 4; +const ANIMATION_FRAME = 4; const ANIMATION_STEP = HALF / ANIMATION_FRAME; function getPosition(index){ @@ -192,4 +192,4 @@ Bangle.on('swipe', dir => { // close launcher when lcd is off Bangle.on('lcdPower', on => { if(!on) return load(); -}); \ No newline at end of file +});