1
0
Fork 0

Merge branch 'master' of github.com:espruino/BangleApps

master
Gordon Williams 2022-05-16 14:35:35 +01:00
commit 22a7de9a87
14 changed files with 331 additions and 115 deletions

View File

@ -2,3 +2,4 @@
0.02: Fix the settings bug and some tweaking 0.02: Fix the settings bug and some tweaking
0.03: Do not alarm while charging 0.03: Do not alarm while charging
0.04: Obey system quiet mode 0.04: Obey system quiet mode
0.05: Battery optimisation, add the pause option, bug fixes

View File

@ -7,8 +7,8 @@ Different settings can be personalized:
- Enable : Enable/Disable the app - Enable : Enable/Disable the app
- Start hour: Hour to start the reminder - Start hour: Hour to start the reminder
- End hour: Hour to end 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 - 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 - Min steps: Minimal amount of steps to count as an activity

View File

@ -1,40 +1,42 @@
function drawAlert(){ function drawAlert() {
E.showPrompt("Inactivity detected",{ E.showPrompt("Inactivity detected", {
title:"Activity reminder", title: "Activity reminder",
buttons : {"Ok": true,"Dismiss": false} buttons: { "Ok": 1, "Dismiss": 2, "Pause": 3 }
}).then(function(v) { }).then(function (v) {
if(v == true){ if (v == 1) {
stepsArray = stepsArray.slice(0, activityreminder.maxInnactivityMin - 3); activityreminder_data.okDate = new Date();
require("activityreminder").saveStepsArray(stepsArray); }
} if (v == 2) {
if(v == false){ activityreminder_data.dismissDate = new Date();
stepsArray = stepsArray.slice(0, activityreminder.maxInnactivityMin - activityreminder.dismissDelayMin); }
require("activityreminder").saveStepsArray(stepsArray); if (v == 3) {
} activityreminder_data.pauseDate = new Date();
}
activityreminder.saveData(activityreminder_data);
load(); load();
}); });
// Obey system quiet mode: // Obey system quiet mode:
if (!(require('Storage').readJSON('setting.json',1)||{}).quiet) { if (!(storage.readJSON('setting.json', 1) || {}).quiet) {
Bangle.buzz(400); Bangle.buzz(400);
} }
setTimeout(load, 20000); setTimeout(load, 20000);
} }
function run(){ function run() {
if(stepsArray.length == activityreminder.maxInnactivityMin){ if (activityreminder.mustAlert(activityreminder_data, activityreminder_settings)) {
if (stepsArray[0] - stepsArray[stepsArray.length-1] < activityreminder.minSteps){ drawAlert();
drawAlert(); } else {
} eval(storage.read("activityreminder.settings.js"))(() => load());
}else{ }
eval(require("Storage").read("activityreminder.settings.js"))(()=>load());
}
} }
const activityreminder = require("activityreminder");
const storage = require("Storage");
g.clear(); g.clear();
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
activityreminder = require("activityreminder").loadSettings(); const activityreminder_settings = activityreminder.loadSettings();
stepsArray = require("activityreminder").loadStepsArray(); const activityreminder_data = activityreminder.loadData();
run(); run();

View File

@ -1,30 +1,45 @@
function run(){ function run() {
if (Bangle.isCharging()) return; if (isNotWorn()) return;
var now = new Date(); let now = new Date();
var h = now.getHours(); let h = now.getHours();
if(h >= activityreminder.startHour && h < activityreminder.endHour){ let health = Bangle.getHealthStatus("day");
var health = Bangle.getHealthStatus("day");
stepsArray.unshift(health.steps); if (h >= activityreminder_settings.startHour && h < activityreminder_settings.endHour) {
stepsArray = stepsArray.slice(0, activityreminder.maxInnactivityMin); if (health.steps - activityreminder_data.stepsOnDate >= activityreminder_settings.minSteps // more steps made than needed
require("activityreminder").saveStepsArray(stepsArray); || health.steps < activityreminder_data.stepsOnDate) { // new day or reboot of the watch
} activityreminder_data.stepsOnDate = health.steps;
else{ activityreminder_data.stepsDate = now;
if(stepsArray != []){ activityreminder.saveData(activityreminder_data);
stepsArray = []; /* todo in a futur release
require("activityreminder").saveStepsArray(stepsArray); add settimer to trigger like 10 secs after the stepsDate + minSteps
cancel all other timers of this app
*/
} }
}
if(stepsArray.length >= activityreminder.maxInnactivityMin){ if(activityreminder.mustAlert(activityreminder_data, activityreminder_settings)){
if (stepsArray[0] - stepsArray[stepsArray.length-1] < activityreminder.minSteps){
load('activityreminder.app.js'); 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(); const activityreminder = require("activityreminder");
if(activityreminder.enabled) { const activityreminder_settings = activityreminder.loadSettings();
stepsArray = require("activityreminder").loadStepsArray(); if (activityreminder_settings.enabled) {
const activityreminder_data = activityreminder.loadData();
if(activityreminder_data.firstLoad){
activityreminder_data.firstLoad =false;
activityreminder.saveData(activityreminder_data);
}
setInterval(run, 60000); 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
*/
} }

View File

@ -1,22 +1,57 @@
exports.loadSettings = function() { const storage = require("Storage");
exports.loadSettings = function () {
return Object.assign({ return Object.assign({
enabled: true, enabled: true,
startHour: 9, startHour: 9,
endHour: 20, endHour: 20,
maxInnactivityMin: 30, maxInnactivityMin: 30,
dismissDelayMin: 15, dismissDelayMin: 15,
pauseDelayMin: 120,
minSteps: 50 minSteps: 50
}, require("Storage").readJSON("activityreminder.s.json", true) || {}); }, storage.readJSON("activityreminder.s.json", true) || {});
}; };
exports.writeSettings = function(settings){ exports.writeSettings = function (settings) {
require("Storage").writeJSON("activityreminder.s.json", settings); storage.writeJSON("activityreminder.s.json", settings);
}; };
exports.saveStepsArray = function(stepsArray) { exports.saveData = function (data) {
require("Storage").writeJSON("activityreminder.sa.json", stepsArray); storage.writeJSON("activityreminder.data.json", data);
}; };
exports.loadStepsArray = function(){ exports.loadData = function () {
return require("Storage").readJSON("activityreminder.sa.json") || []; 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;
}

View File

@ -3,7 +3,7 @@
"name": "Activity Reminder", "name": "Activity Reminder",
"shortName":"Activity Reminder", "shortName":"Activity Reminder",
"description": "A reminder to take short walks for the ones with a sedentary lifestyle", "description": "A reminder to take short walks for the ones with a sedentary lifestyle",
"version":"0.04", "version":"0.05",
"icon": "app.png", "icon": "app.png",
"type": "app", "type": "app",
"tags": "tool,activity", "tags": "tool,activity",
@ -18,6 +18,6 @@
], ],
"data": [ "data": [
{"name": "activityreminder.s.json"}, {"name": "activityreminder.s.json"},
{"name": "activityreminder.sa.json"} {"name": "activityreminder.data.json"}
] ]
} }

View File

@ -1,64 +1,76 @@
(function(back) { (function (back) {
// Load settings // Load settings
var settings = require("activityreminder").loadSettings(); const activityreminder = require("activityreminder");
const settings = activityreminder.loadSettings();
// Show the menu // Show the menu
E.showMenu({ E.showMenu({
"" : { "title" : "Activity Reminder" }, "": { "title": "Activity Reminder" },
"< Back" : () => back(), "< Back": () => back(),
'Enable': { 'Enable': {
value: settings.enabled, value: settings.enabled,
format: v => v?"Yes":"No", format: v => v ? "Yes" : "No",
onchange: v => { onchange: v => {
settings.enabled = v; settings.enabled = v;
require("activityreminder").writeSettings(settings); 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': { format: x => {
value: settings.startHour, return x + " min";
min: 0, max: 24, }
onchange: v => { },
settings.startHour = v; 'Dismiss delay': {
require("activityreminder").writeSettings(settings); value: settings.dismissDelayMin,
} min: 5, max: 60,
}, onchange: v => {
'End hour': { settings.dismissDelayMin = v;
value: settings.endHour, activityreminder.writeSettings(settings);
min: 0, max: 24, },
onchange: v => { format: x => {
settings.endHour = v; return x + " min";
require("activityreminder").writeSettings(settings); }
} },
}, 'Pause delay': {
'Max inactivity': { value: settings.pauseDelayMin,
value: settings.maxInnactivityMin, min: 30, max: 240,
min: 15, max: 120, onchange: v => {
onchange: v => { settings.pauseDelayMin = v;
settings.maxInnactivityMin = v; activityreminder.writeSettings(settings);
require("activityreminder").writeSettings(settings); },
}, format: x => {
format: x => { return x + " min";
return x + " min"; }
} },
}, 'Min steps': {
'Dismiss delay': { value: settings.minSteps,
value: settings.dismissDelayMin, min: 10, max: 500,
min: 5, max: 60, onchange: v => {
onchange: v => { settings.minSteps = v;
settings.dismissDelayMin = v; activityreminder.writeSettings(settings);
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);
}
}
}); });
}) })

View File

@ -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.

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwkB/4AJ+EPBhQXg+BBDCyJaGGR5zIDBoQEL4QYOLYR3GBIouJR5AYBGBILBU5QMGFwgiFX4wwIEI4XGGBAgHd44+HD44XHNw4XWM5IIHCIoXWV5IXICQgXvLxAAKCYYXh5nMC6n8C4PPC5MAAA8PC4ZxBACAXOI653hU5zvJABASEC5PwHI4XcMBIXICIoXXJBAXHCAwXXJBAXHB5AfGC4ygJEAwXGQ5BoIQxoiDBYgXECwIuIBgb5ECIQJFGBQmCC4QHEDBwAFCxoYICx5ZELZoZJFiIXpA="))

85
apps/calibration/app.js Normal file
View File

@ -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();

14
apps/calibration/boot.js Normal file
View File

@ -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;
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

View File

@ -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"}]
}

View File

@ -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();
}
},
});
})