diff --git a/apps/activityreminder/ChangeLog b/apps/activityreminder/ChangeLog index ef387d098..d4b5100a2 100644 --- a/apps/activityreminder/ChangeLog +++ b/apps/activityreminder/ChangeLog @@ -2,3 +2,4 @@ 0.02: Fix the settings bug and some tweaking 0.03: Do not alarm while charging 0.04: Obey system quiet mode +0.05: Battery optimisation, add the pause option, bug fixes diff --git a/apps/activityreminder/README.md b/apps/activityreminder/README.md index e8be66f3c..25e2c8d35 100644 --- a/apps/activityreminder/README.md +++ b/apps/activityreminder/README.md @@ -7,8 +7,8 @@ Different settings can be personalized: - Enable : Enable/Disable the app - Start hour: Hour to start the reminder - End hour: Hour to end the reminder -- Max inactivity: Maximum inactivity time to allow before the alert. From 15 to 60 min +- Max inactivity: Maximum inactivity time to allow before the alert. From 15 to 120 min - Dismiss delay: Delay added before the next alert if the alert is dismissed. From 5 to 60 min - Notice: If Dissmiss delay > Max inactivity then it will be equal Max inactivity +- Pause delay: Same as Dismiss delay but longer (usefull for meetings and such). From 30 to 240 min - Min steps: Minimal amount of steps to count as an activity diff --git a/apps/activityreminder/app.js b/apps/activityreminder/app.js index 811399ca6..f3d72976e 100644 --- a/apps/activityreminder/app.js +++ b/apps/activityreminder/app.js @@ -1,40 +1,42 @@ -function drawAlert(){ - E.showPrompt("Inactivity detected",{ - title:"Activity reminder", - buttons : {"Ok": true,"Dismiss": false} - }).then(function(v) { - if(v == true){ - stepsArray = stepsArray.slice(0, activityreminder.maxInnactivityMin - 3); - require("activityreminder").saveStepsArray(stepsArray); - } - if(v == false){ - stepsArray = stepsArray.slice(0, activityreminder.maxInnactivityMin - activityreminder.dismissDelayMin); - require("activityreminder").saveStepsArray(stepsArray); - } +function drawAlert() { + E.showPrompt("Inactivity detected", { + title: "Activity reminder", + buttons: { "Ok": 1, "Dismiss": 2, "Pause": 3 } + }).then(function (v) { + if (v == 1) { + activityreminder_data.okDate = new Date(); + } + if (v == 2) { + activityreminder_data.dismissDate = new Date(); + } + if (v == 3) { + activityreminder_data.pauseDate = new Date(); + } + activityreminder.saveData(activityreminder_data); load(); }); // Obey system quiet mode: - if (!(require('Storage').readJSON('setting.json',1)||{}).quiet) { + if (!(storage.readJSON('setting.json', 1) || {}).quiet) { Bangle.buzz(400); } setTimeout(load, 20000); } -function run(){ - if(stepsArray.length == activityreminder.maxInnactivityMin){ - if (stepsArray[0] - stepsArray[stepsArray.length-1] < activityreminder.minSteps){ - drawAlert(); - } - }else{ - eval(require("Storage").read("activityreminder.settings.js"))(()=>load()); - } +function run() { + if (activityreminder.mustAlert(activityreminder_data, activityreminder_settings)) { + drawAlert(); + } else { + eval(storage.read("activityreminder.settings.js"))(() => load()); + } } +const activityreminder = require("activityreminder"); +const storage = require("Storage"); g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); -activityreminder = require("activityreminder").loadSettings(); -stepsArray = require("activityreminder").loadStepsArray(); +const activityreminder_settings = activityreminder.loadSettings(); +const activityreminder_data = activityreminder.loadData(); run(); diff --git a/apps/activityreminder/boot.js b/apps/activityreminder/boot.js index 09aa9d757..7c094f521 100644 --- a/apps/activityreminder/boot.js +++ b/apps/activityreminder/boot.js @@ -1,30 +1,45 @@ -function run(){ - if (Bangle.isCharging()) return; - var now = new Date(); - var h = now.getHours(); - if(h >= activityreminder.startHour && h < activityreminder.endHour){ - var health = Bangle.getHealthStatus("day"); - stepsArray.unshift(health.steps); - stepsArray = stepsArray.slice(0, activityreminder.maxInnactivityMin); - require("activityreminder").saveStepsArray(stepsArray); - } - else{ - if(stepsArray != []){ - stepsArray = []; - require("activityreminder").saveStepsArray(stepsArray); +function run() { + if (isNotWorn()) return; + let now = new Date(); + let h = now.getHours(); + let health = Bangle.getHealthStatus("day"); + + if (h >= activityreminder_settings.startHour && h < activityreminder_settings.endHour) { + if (health.steps - activityreminder_data.stepsOnDate >= activityreminder_settings.minSteps // more steps made than needed + || health.steps < activityreminder_data.stepsOnDate) { // new day or reboot of the watch + activityreminder_data.stepsOnDate = health.steps; + activityreminder_data.stepsDate = now; + activityreminder.saveData(activityreminder_data); + /* todo in a futur release + add settimer to trigger like 10 secs after the stepsDate + minSteps + cancel all other timers of this app + */ } - } - if(stepsArray.length >= activityreminder.maxInnactivityMin){ - if (stepsArray[0] - stepsArray[stepsArray.length-1] < activityreminder.minSteps){ + + if(activityreminder.mustAlert(activityreminder_data, activityreminder_settings)){ load('activityreminder.app.js'); } } + } +function isNotWorn() { + // todo in a futur release check temperature and mouvement in a futur release + return Bangle.isCharging(); +} -activityreminder = require("activityreminder").loadSettings(); -if(activityreminder.enabled) { - stepsArray = require("activityreminder").loadStepsArray(); +const activityreminder = require("activityreminder"); +const activityreminder_settings = activityreminder.loadSettings(); +if (activityreminder_settings.enabled) { + const activityreminder_data = activityreminder.loadData(); + if(activityreminder_data.firstLoad){ + activityreminder_data.firstLoad =false; + activityreminder.saveData(activityreminder_data); + } setInterval(run, 60000); + /* todo in a futur release + increase setInterval time to something that is still sensible (5 mins ?) + add settimer to trigger like 10 secs after the stepsDate + minSteps + cancel all other timers of this app + */ } - diff --git a/apps/activityreminder/lib.js b/apps/activityreminder/lib.js index 712842fba..5b7959827 100644 --- a/apps/activityreminder/lib.js +++ b/apps/activityreminder/lib.js @@ -1,22 +1,57 @@ -exports.loadSettings = function() { +const storage = require("Storage"); + +exports.loadSettings = function () { return Object.assign({ enabled: true, startHour: 9, endHour: 20, maxInnactivityMin: 30, dismissDelayMin: 15, + pauseDelayMin: 120, minSteps: 50 - }, require("Storage").readJSON("activityreminder.s.json", true) || {}); + }, storage.readJSON("activityreminder.s.json", true) || {}); }; -exports.writeSettings = function(settings){ - require("Storage").writeJSON("activityreminder.s.json", settings); +exports.writeSettings = function (settings) { + storage.writeJSON("activityreminder.s.json", settings); }; -exports.saveStepsArray = function(stepsArray) { - require("Storage").writeJSON("activityreminder.sa.json", stepsArray); +exports.saveData = function (data) { + storage.writeJSON("activityreminder.data.json", data); }; -exports.loadStepsArray = function(){ - return require("Storage").readJSON("activityreminder.sa.json") || []; -}; \ No newline at end of file +exports.loadData = function () { + let health = Bangle.getHealthStatus("day"); + const data = Object.assign({ + firstLoad: true, + stepsDate: new Date(), + stepsOnDate: health.steps, + okDate: new Date(1970), + dismissDate: new Date(1970), + pauseDate: new Date(1970), + }, + storage.readJSON("activityreminder.data.json") || {}); + + if(typeof(data.stepsDate) == "string") + data.stepsDate = new Date(data.stepsDate); + if(typeof(data.okDate) == "string") + data.okDate = new Date(data.okDate); + if(typeof(data.dismissDate) == "string") + data.dismissDate = new Date(data.dismissDate); + if(typeof(data.pauseDate) == "string") + data.pauseDate = new Date(data.pauseDate); + + return data; +}; + +exports.mustAlert = function(activityreminder_data, activityreminder_settings) { + let now = new Date(); + if ((now - activityreminder_data.stepsDate) / 60000 > activityreminder_settings.maxInnactivityMin) { // inactivity detected + if ((now - activityreminder_data.okDate) / 60000 > 3 && // last alert anwsered with ok was more than 3 min ago + (now - activityreminder_data.dismissDate) / 60000 > activityreminder_settings.dismissDelayMin && // last alert was more than dismissDelayMin ago + (now - activityreminder_data.pauseDate) / 60000 > activityreminder_settings.pauseDelayMin) { // last alert was more than pauseDelayMin ago + return true; + } + } + return false; +} \ No newline at end of file diff --git a/apps/activityreminder/metadata.json b/apps/activityreminder/metadata.json index 89b0fbc0b..15f10f2ed 100644 --- a/apps/activityreminder/metadata.json +++ b/apps/activityreminder/metadata.json @@ -3,7 +3,7 @@ "name": "Activity Reminder", "shortName":"Activity Reminder", "description": "A reminder to take short walks for the ones with a sedentary lifestyle", - "version":"0.04", + "version":"0.05", "icon": "app.png", "type": "app", "tags": "tool,activity", @@ -18,6 +18,6 @@ ], "data": [ {"name": "activityreminder.s.json"}, - {"name": "activityreminder.sa.json"} + {"name": "activityreminder.data.json"} ] } diff --git a/apps/activityreminder/settings.js b/apps/activityreminder/settings.js index e4f44efc6..9dff61f48 100644 --- a/apps/activityreminder/settings.js +++ b/apps/activityreminder/settings.js @@ -1,64 +1,76 @@ -(function(back) { +(function (back) { // Load settings - var settings = require("activityreminder").loadSettings(); + const activityreminder = require("activityreminder"); + const settings = activityreminder.loadSettings(); // Show the menu E.showMenu({ - "" : { "title" : "Activity Reminder" }, - "< Back" : () => back(), - 'Enable': { - value: settings.enabled, - format: v => v?"Yes":"No", - onchange: v => { - settings.enabled = v; - require("activityreminder").writeSettings(settings); - } + "": { "title": "Activity Reminder" }, + "< Back": () => back(), + 'Enable': { + value: settings.enabled, + format: v => v ? "Yes" : "No", + onchange: v => { + settings.enabled = v; + activityreminder.writeSettings(settings); + } + }, + 'Start hour': { + value: settings.startHour, + min: 0, max: 24, + onchange: v => { + settings.startHour = v; + activityreminder.writeSettings(settings); + } + }, + 'End hour': { + value: settings.endHour, + min: 0, max: 24, + onchange: v => { + settings.endHour = v; + activityreminder.writeSettings(settings); + } + }, + 'Max inactivity': { + value: settings.maxInnactivityMin, + min: 15, max: 120, + onchange: v => { + settings.maxInnactivityMin = v; + activityreminder.writeSettings(settings); }, - 'Start hour': { - value: settings.startHour, - min: 0, max: 24, - onchange: v => { - settings.startHour = v; - require("activityreminder").writeSettings(settings); - } - }, - 'End hour': { - value: settings.endHour, - min: 0, max: 24, - onchange: v => { - settings.endHour = v; - require("activityreminder").writeSettings(settings); - } - }, - 'Max inactivity': { - value: settings.maxInnactivityMin, - min: 15, max: 120, - onchange: v => { - settings.maxInnactivityMin = v; - require("activityreminder").writeSettings(settings); - }, - format: x => { - return x + " min"; - } - }, - 'Dismiss delay': { - value: settings.dismissDelayMin, - min: 5, max: 60, - onchange: v => { - settings.dismissDelayMin = v; - require("activityreminder").writeSettings(settings); - }, - format: x => { - return x + " min"; - } - }, - 'Min steps': { - value: settings.minSteps, - min: 10, max: 500, - onchange: v => { - settings.minSteps = v; - require("activityreminder").writeSettings(settings); - } - } + format: x => { + return x + " min"; + } + }, + 'Dismiss delay': { + value: settings.dismissDelayMin, + min: 5, max: 60, + onchange: v => { + settings.dismissDelayMin = v; + activityreminder.writeSettings(settings); + }, + format: x => { + return x + " min"; + } + }, + 'Pause delay': { + value: settings.pauseDelayMin, + min: 30, max: 240, + onchange: v => { + settings.pauseDelayMin = v; + activityreminder.writeSettings(settings); + }, + format: x => { + return x + " min"; + } + }, + 'Min steps': { + value: settings.minSteps, + min: 10, max: 500, + onchange: v => { + settings.minSteps = v; + activityreminder.writeSettings(settings); + } + } }); }) diff --git a/apps/calibration/README.md b/apps/calibration/README.md new file mode 100644 index 000000000..37f637d21 --- /dev/null +++ b/apps/calibration/README.md @@ -0,0 +1,11 @@ +# Banglejs - Touchscreen calibration +A simple calibration app for the touchscreen + +## Usage + +Once lauched touch the cross that appear on the screen to make +another spawn elsewhere. + +each new touch on the screen will help to calibrate the offset +of your finger on the screen. After five or more input, press +the button to save the calibration and close the application. \ No newline at end of file diff --git a/apps/calibration/app-icon.js b/apps/calibration/app-icon.js new file mode 100644 index 000000000..af66c3f68 --- /dev/null +++ b/apps/calibration/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkB/4AJ+EPBhQXg+BBDCyJaGGR5zIDBoQEL4QYOLYR3GBIouJR5AYBGBILBU5QMGFwgiFX4wwIEI4XGGBAgHd44+HD44XHNw4XWM5IIHCIoXWV5IXICQgXvLxAAKCYYXh5nMC6n8C4PPC5MAAA8PC4ZxBACAXOI653hU5zvJABASEC5PwHI4XcMBIXICIoXXJBAXHCAwXXJBAXHB5AfGC4ygJEAwXGQ5BoIQxoiDBYgXECwIuIBgb5ECIQJFGBQmCC4QHEDBwAFCxoYICx5ZELZoZJFiIXpA=")) \ No newline at end of file diff --git a/apps/calibration/app.js b/apps/calibration/app.js new file mode 100644 index 000000000..d3823de63 --- /dev/null +++ b/apps/calibration/app.js @@ -0,0 +1,85 @@ +class BanglejsApp { + constructor() { + this.x = 0; + this.y = 0; + this.settings = { + xoffset: 0, + yoffset: 0, + }; + } + + load_settings() { + let settings = require('Storage').readJSON('calibration.json', true) || {active: false}; + + // do nothing if the calibration is deactivated + if (settings.active === true) { + // cancel the calibration offset + Bangle.on('touch', function(button, xy) { + xy.x += settings.xoffset; + xy.y += settings.yoffset; + }); + } + if (!settings.xoffset) settings.xoffset = 0; + if (!settings.yoffset) settings.yoffset = 0; + + console.log('loaded settings:'); + console.log(settings); + + return settings; + } + + save_settings() { + this.settings.active = true; + this.settings.reload = false; + require('Storage').writeJSON('calibration.json', this.settings); + + console.log('saved settings:'); + console.log(this.settings); + } + + explain() { + /* + * TODO: + * Present how to use the application + * + */ + } + + drawTarget() { + this.x = 16 + Math.floor(Math.random() * (g.getWidth() - 32)); + this.y = 40 + Math.floor(Math.random() * (g.getHeight() - 80)); + + g.clearRect(0, 24, g.getWidth(), g.getHeight() - 24); + g.drawLine(this.x, this.y - 5, this.x, this.y + 5); + g.drawLine(this.x - 5, this.y, this.x + 5, this.y); + g.setFont('Vector', 10); + g.drawString('current offset: ' + this.settings.xoffset + ', ' + this.settings.yoffset, 0, 24); + } + + setOffset(xy) { + this.settings.xoffset = Math.round((this.settings.xoffset + (this.x - Math.floor((this.x + xy.x)/2)))/2); + this.settings.yoffset = Math.round((this.settings.yoffset + (this.y - Math.floor((this.y + xy.y)/2)))/2); + } +} + + +E.srand(Date.now()); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +calibration = new BanglejsApp(); +calibration.load_settings(); + +let modes = { + mode : 'custom', + btn : function(n) { + calibration.save_settings(this.settings); + load(); + }, + touch : function(btn, xy) { + calibration.setOffset(xy); + calibration.drawTarget(); + }, +}; +Bangle.setUI(modes); +calibration.drawTarget(); diff --git a/apps/calibration/boot.js b/apps/calibration/boot.js new file mode 100644 index 000000000..237fb2e0d --- /dev/null +++ b/apps/calibration/boot.js @@ -0,0 +1,14 @@ +let cal_settings = require('Storage').readJSON("calibration.json", true) || {active: false}; +Bangle.on('touch', function(button, xy) { + // do nothing if the calibration is deactivated + if (cal_settings.active === false) return; + + // reload the calibration offset at each touch event /!\ bad for the flash memory + if (cal_settings.reload === true) { + cal_settings = require('Storage').readJSON("calibration.json", true); + } + + // apply the calibration offset + xy.x += cal_settings.xoffset; + xy.y += cal_settings.yoffset; +}); diff --git a/apps/calibration/calibration.png b/apps/calibration/calibration.png new file mode 100644 index 000000000..3fb44beee Binary files /dev/null and b/apps/calibration/calibration.png differ diff --git a/apps/calibration/metadata.json b/apps/calibration/metadata.json new file mode 100644 index 000000000..122a2c175 --- /dev/null +++ b/apps/calibration/metadata.json @@ -0,0 +1,17 @@ +{ "id": "calibration", + "name": "Touchscreen Calibration", + "shortName":"Calibration", + "icon": "calibration.png", + "version":"1.00", + "description": "A simple calibration app for the touchscreen", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "tags": "tool", + "storage": [ + {"name":"calibration.app.js","url":"app.js"}, + {"name":"calibration.boot.js","url":"boot.js"}, + {"name":"calibration.settings.js","url":"settings.js"}, + {"name":"calibration.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"calibration.json"}] +} diff --git a/apps/calibration/settings.js b/apps/calibration/settings.js new file mode 100644 index 000000000..6db8dd3bb --- /dev/null +++ b/apps/calibration/settings.js @@ -0,0 +1,23 @@ +(function(back) { + var FILE = "calibration.json"; + var settings = Object.assign({ + active: true, + }, require('Storage').readJSON(FILE, true) || {}); + + function writeSettings() { + require('Storage').writeJSON(FILE, settings); + } + + E.showMenu({ + "" : { "title" : "Calibration" }, + "< Back" : () => back(), + 'Active': { + value: !!settings.active, + format: v => v? "On":"Off", + onchange: v => { + settings.active = v; + writeSettings(); + } + }, + }); +}) \ No newline at end of file