Merge branch 'master' of https://github.com/espruino/BangleApps
commit
22e8926d95
28
apps.json
28
apps.json
|
|
@ -41,7 +41,7 @@
|
||||||
"name": "Default Launcher",
|
"name": "Default Launcher",
|
||||||
"shortName":"Launcher",
|
"shortName":"Launcher",
|
||||||
"icon": "app.png",
|
"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.",
|
"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",
|
"tags": "tool,system,launcher",
|
||||||
"type":"launch",
|
"type":"launch",
|
||||||
|
|
@ -411,7 +411,7 @@
|
||||||
{ "id": "swatch",
|
{ "id": "swatch",
|
||||||
"name": "Stopwatch",
|
"name": "Stopwatch",
|
||||||
"icon": "stopwatch.png",
|
"icon": "stopwatch.png",
|
||||||
"version":"0.05",
|
"version":"0.06",
|
||||||
"interface": "interface.html",
|
"interface": "interface.html",
|
||||||
"description": "Simple stopwatch with Lap Time logging to a JSON file",
|
"description": "Simple stopwatch with Lap Time logging to a JSON file",
|
||||||
"tags": "health",
|
"tags": "health",
|
||||||
|
|
@ -1050,7 +1050,7 @@
|
||||||
"name": "Touch Launcher",
|
"name": "Touch Launcher",
|
||||||
"shortName":"Menu",
|
"shortName":"Menu",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.05",
|
"version":"0.06",
|
||||||
"description": "Touch enable left to right launcher.",
|
"description": "Touch enable left to right launcher.",
|
||||||
"tags": "tool,system,launcher",
|
"tags": "tool,system,launcher",
|
||||||
"type":"launch",
|
"type":"launch",
|
||||||
|
|
@ -1127,16 +1127,31 @@
|
||||||
"name": "Active Pedometer",
|
"name": "Active Pedometer",
|
||||||
"shortName":"Active Pedometer",
|
"shortName":"Active Pedometer",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.01",
|
"version":"0.02",
|
||||||
"description": "Pedometer that filters out arm movement and displays a step goal progress.",
|
"description": "Pedometer that filters out arm movement and displays a step goal progress.",
|
||||||
"tags": "outdoors,widget",
|
"tags": "outdoors,widget",
|
||||||
"type":"widget",
|
"type":"widget",
|
||||||
|
"readme": "README.md",
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"activepedom.wid.js","url":"widget.js"},
|
{"name":"activepedom.wid.js","url":"widget.js"},
|
||||||
{"name":"activepedom.settings.js","url":"settings.js"},
|
{"name":"activepedom.settings.js","url":"settings.js"},
|
||||||
{"name":"activepedom.img","url":"app-icon.js","evaluate":true}
|
{"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",
|
{ "id": "tabata",
|
||||||
"name": "Tabata",
|
"name": "Tabata",
|
||||||
"shortName": "Tabata - Control High-Intensity Interval Training",
|
"shortName": "Tabata - Control High-Intensity Interval Training",
|
||||||
|
|
@ -1206,7 +1221,7 @@
|
||||||
"name": "Numerals Clock",
|
"name": "Numerals Clock",
|
||||||
"shortName": "Numerals Clock",
|
"shortName": "Numerals Clock",
|
||||||
"icon": "numerals.png",
|
"icon": "numerals.png",
|
||||||
"version":"0.02",
|
"version":"0.03",
|
||||||
"description": "A simple big numerals clock",
|
"description": "A simple big numerals clock",
|
||||||
"tags": "numerals,clock",
|
"tags": "numerals,clock",
|
||||||
"type":"clock",
|
"type":"clock",
|
||||||
|
|
@ -1214,7 +1229,8 @@
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"numerals.app.js","url":"numerals.app.js"},
|
{"name":"numerals.app.js","url":"numerals.app.js"},
|
||||||
{"name":"numerals.img","url":"numerals-icon.js","evaluate":true},
|
{"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",
|
{ "id": "bledetect",
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
0.01: New Widget!
|
0.01: New Widget!
|
||||||
|
0.02: Distance calculation and display
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Improved pedometer
|
# Active Pedometer
|
||||||
Pedometer that filters out arm movement and displays a step goal progress.
|
Pedometer that filters out arm movement and displays a step goal progress.
|
||||||
|
|
||||||
I changed the step counting algorithm completely.
|
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
|
## Features
|
||||||
|
|
||||||
* Two line display
|
* Two line display
|
||||||
|
* Can display distance (in km) or steps in each line
|
||||||
* Large number for good readability
|
* 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'
|
* Large number is displayed in green when status is 'active'
|
||||||
* Progress bar for step goal
|
* Progress bar for step goal
|
||||||
* Counts steps only if they are reached in a certain time
|
* 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)
|
* 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
|
* 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
|
## Requests
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
*/
|
*/
|
||||||
(function(back) {
|
(function(back) {
|
||||||
const SETTINGS_FILE = 'activepedom.settings.json';
|
const SETTINGS_FILE = 'activepedom.settings.json';
|
||||||
|
const LINES = ['Steps', 'Distance'];
|
||||||
|
|
||||||
// initialize with default settings...
|
// initialize with default settings...
|
||||||
let s = {
|
let s = {
|
||||||
|
|
@ -13,6 +14,9 @@
|
||||||
'intervalResetActive' : 30000,
|
'intervalResetActive' : 30000,
|
||||||
'stepSensitivity' : 80,
|
'stepSensitivity' : 80,
|
||||||
'stepGoal' : 10000,
|
'stepGoal' : 10000,
|
||||||
|
'stepLength' : 75,
|
||||||
|
'lineOne': LINES[0],
|
||||||
|
'lineTwo': LINES[1],
|
||||||
};
|
};
|
||||||
// ...and overwrite them with any saved values
|
// ...and overwrite them with any saved values
|
||||||
// This way saved values are preserved if a new version adds more settings
|
// This way saved values are preserved if a new version adds more settings
|
||||||
|
|
@ -27,7 +31,7 @@
|
||||||
return function (value) {
|
return function (value) {
|
||||||
s[key] = value;
|
s[key] = value;
|
||||||
storage.write(SETTINGS_FILE, s);
|
storage.write(SETTINGS_FILE, s);
|
||||||
WIDGETS["activepedom"].draw();
|
//WIDGETS["activepedom"].draw();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,6 +80,33 @@
|
||||||
step: 1000,
|
step: 1000,
|
||||||
onchange: save('stepGoal'),
|
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);
|
E.showMenu(menu);
|
||||||
});
|
});
|
||||||
|
|
@ -8,22 +8,16 @@
|
||||||
var active = 0; //x steps in y seconds achieved
|
var active = 0; //x steps in y seconds achieved
|
||||||
var stepGoalPercent = 0; //percentage of step goal
|
var stepGoalPercent = 0; //percentage of step goal
|
||||||
var stepGoalBarLength = 0; //length og progress bar
|
var stepGoalBarLength = 0; //length og progress bar
|
||||||
var lastUpdate = new Date();
|
var lastUpdate = new Date(); //used to reset counted steps on new day
|
||||||
var width = 45;
|
var width = 45; //width of widget
|
||||||
|
|
||||||
|
//used for statistics and debugging
|
||||||
var stepsTooShort = 0;
|
var stepsTooShort = 0;
|
||||||
var stepsTooLong = 0;
|
var stepsTooLong = 0;
|
||||||
var stepsOutsideTime = 0;
|
var stepsOutsideTime = 0;
|
||||||
|
|
||||||
//define default settings
|
var distance = 0; //distance travelled
|
||||||
const DEFAULTS = {
|
|
||||||
'cMaxTime' : 1100,
|
|
||||||
'cMinTime' : 240,
|
|
||||||
'stepThreshold' : 30,
|
|
||||||
'intervalResetActive' : 30000,
|
|
||||||
'stepSensitivity' : 80,
|
|
||||||
'stepGoal' : 10000,
|
|
||||||
};
|
|
||||||
const SETTINGS_FILE = 'activepedom.settings.json';
|
const SETTINGS_FILE = 'activepedom.settings.json';
|
||||||
const PEDOMFILE = "activepedom.steps.json";
|
const PEDOMFILE = "activepedom.steps.json";
|
||||||
|
|
||||||
|
|
@ -32,8 +26,19 @@
|
||||||
function loadSettings() {
|
function loadSettings() {
|
||||||
settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {};
|
settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {};
|
||||||
}
|
}
|
||||||
|
|
||||||
//return setting
|
//return setting
|
||||||
function setting(key) {
|
function setting(key) {
|
||||||
|
//define default settings
|
||||||
|
const DEFAULTS = {
|
||||||
|
'cMaxTime' : 1100,
|
||||||
|
'cMinTime' : 240,
|
||||||
|
'stepThreshold' : 30,
|
||||||
|
'intervalResetActive' : 30000,
|
||||||
|
'stepSensitivity' : 80,
|
||||||
|
'stepGoal' : 10000,
|
||||||
|
'stepLength' : 75,
|
||||||
|
};
|
||||||
if (!settings) { loadSettings(); }
|
if (!settings) { loadSettings(); }
|
||||||
return (key in settings) ? settings[key] : DEFAULTS[key];
|
return (key in settings) ? settings[key] : DEFAULTS[key];
|
||||||
}
|
}
|
||||||
|
|
@ -46,7 +51,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
//format number to make them shorter
|
//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 <= 999) return num; //smaller 1.000, return 600 as 600
|
||||||
if (num >= 1000 && num < 10000) { //between 1.000 and 10.000
|
if (num >= 1000 && num < 10000) { //between 1.000 and 10.000
|
||||||
num = Math.floor(num/100)*100;
|
num = Math.floor(num/100)*100;
|
||||||
|
|
@ -99,11 +104,12 @@
|
||||||
else {
|
else {
|
||||||
stepsOutsideTime++;
|
stepsOutsideTime++;
|
||||||
}
|
}
|
||||||
|
settings = 0; //reset settings to save memory
|
||||||
}
|
}
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
var height = 23; //width is deined globally
|
var height = 23; //width is deined globally
|
||||||
var stepsDisplayLarge = kFormatter(stepsCounted);
|
distance = (stepsCounted * setting('stepLength')) / 100 /1000 //distance in km
|
||||||
|
|
||||||
//Check if same day
|
//Check if same day
|
||||||
let date = new Date();
|
let date = new Date();
|
||||||
|
|
@ -121,10 +127,21 @@
|
||||||
if (active == 1) g.setColor(0x07E0); //green
|
if (active == 1) g.setColor(0x07E0); //green
|
||||||
else g.setColor(0xFFFF); //white
|
else g.setColor(0xFFFF); //white
|
||||||
g.setFont("6x8", 2);
|
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.setFont("6x8", 1);
|
||||||
g.setColor(0xFFFF); //white
|
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
|
//draw step goal bar
|
||||||
stepGoalPercent = (stepsCounted / setting('stepGoal')) * 100;
|
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, 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+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
|
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()
|
//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
|
//Read data from file and set variables
|
||||||
let pedomData = require("Storage").readJSON(PEDOMFILE,1);
|
let pedomData = require("Storage").readJSON(PEDOMFILE,1);
|
||||||
|
|
||||||
if (pedomData) {
|
if (pedomData) {
|
||||||
if (pedomData.lastUpdate) lastUpdate = new Date(pedomData.lastUpdate);
|
if (pedomData.lastUpdate) lastUpdate = new Date(pedomData.lastUpdate);
|
||||||
stepsCounted = pedomData.stepsToday|0;
|
stepsCounted = pedomData.stepsToday|0;
|
||||||
|
|
@ -172,6 +192,8 @@
|
||||||
stepsOutsideTime = pedomData.stepsOutsideTime;
|
stepsOutsideTime = pedomData.stepsOutsideTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pedomdata = 0; //reset pedomdata to save memory
|
||||||
|
|
||||||
setStepSensitivity(setting('stepSensitivity')); //set step sensitivity (80 is standard, 400 is muss less sensitive)
|
setStepSensitivity(setting('stepSensitivity')); //set step sensitivity (80 is standard, 400 is muss less sensitive)
|
||||||
|
|
||||||
//Add widget
|
//Add widget
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: New widget and app!
|
||||||
|
|
@ -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/
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwwIFCn/8BYYFRABcD4AFFgIFCh/wgeAAoP//8HCYMDAoPD8EAg4FB8PwgEf+EP/H4HQOAgP8uEAvwfBv0ggBFCn4CB/EBwEfgEB+AFBh+AgfgAoI1BIoQJB4AHBAoXgg4uBAIIFCCYQFGh5rDJQJUBK4IFCNYIFVDoopDGoJiBHYYFKVYRZBWIYDBA4IFBNIQzBG4IbBToKkBAQKVFUIYICVoQUCXIQmCYoIsCaITqDAoLvDNYUAA="))
|
||||||
|
|
@ -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();
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
|
|
@ -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();
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
0.01: New App!
|
||||||
|
0.02: Only store relevant app data (saves RAM when many apps)
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
var s = require("Storage");
|
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)=>{
|
apps.sort((a,b)=>{
|
||||||
var n=(0|a.sortorder)-(0|b.sortorder);
|
var n=(0|a.sortorder)-(0|b.sortorder);
|
||||||
if (n) return n; // do sortorder first
|
if (n) return n; // do sortorder first
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ var locales = {
|
||||||
int_curr_symbol: "ILS",
|
int_curr_symbol: "ILS",
|
||||||
speed: "kmh",
|
speed: "kmh",
|
||||||
distance: { 0: "m", 1: "km" },
|
distance: { 0: "m", 1: "km" },
|
||||||
temperature: "°F",
|
temperature: "°C",
|
||||||
ampm: { 0: "am", 1: "pm" },
|
ampm: { 0: "am", 1: "pm" },
|
||||||
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
|
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
|
datePattern: { 0: "%A, %B %d, %Y", "1": "%d/%m/%Y" }, // Sunday, 1 March 2020 // 01/03/2020
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
0.02: Use BTN2 for settings menu like other clocks
|
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
|
||||||
|
|
@ -5,13 +5,16 @@ Settings can be accessed through the app/widget settings menu of the Bangle.js
|
||||||
|
|
||||||
## Settings available
|
## Settings available
|
||||||
|
|
||||||
### color:
|
### Color:
|
||||||
* rnd - shows numerals in different color combinations every time the watches wakes
|
* rnd - shows numerals in different color combinations every time the watches wakes
|
||||||
* r/g - red/green
|
* r/g - red/green
|
||||||
* y/w - yellow/white
|
* y/w - yellow/white
|
||||||
* o/c - orange/cyan
|
* o/c - orange/cyan
|
||||||
* b/y - blue/yellow'ish
|
* b/y - blue/yellow'ish
|
||||||
|
|
||||||
### draw mode
|
### Draw mode
|
||||||
* fill - fill numerals
|
* fill - fill numerals
|
||||||
* frame - only shows outline of numerals
|
* frame - only shows outline of numerals
|
||||||
|
|
||||||
|
### Menu button
|
||||||
|
* choose button to start launcher menu with
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
color:0,
|
||||||
|
drawMode:"fill",
|
||||||
|
menuButton:22
|
||||||
|
}
|
||||||
|
|
@ -1 +1 @@
|
||||||
require("heatshrink").decompress(atob("mEwwhC/ABMBzIADyAJIAAkQBoMZBIoXCBIwADyIkIGAIuKGAQkIBJIwEEKQANC/4XWR58RiIHFWpAXFe4QRFcpAXFewQRFcxAXEFwQwGA4QXKiAXDGAgX/C/4X/C/4X/C7uQCwcBBwYXNBwYuEC54wCFwgXPzMRiIHFC54AHC/4XiCAoXRhIHDyK3GAAwOBJA0QG45VGC4YwCD4YwKFwgABcgIfEAwIAHBwgA/AAgA=="))
|
require("heatshrink").decompress(atob("mEwwhC/ABXdAAfQBJAAEBgUNBJ4mGBKAmFEhAuLEwQhSABoX/C6yPPYw61IB4r3DHxoIFCwQIHC5YuDCIo3HC4oWEBI4X/C/4X/C/4X/C7XQC4gOEC5gwEBA4XLGAYOFC5oPCA44XNAA4X/C8SAGC6q4CCxb4EG5guICAgfIFxQA/ADg"))
|
||||||
|
|
@ -7,17 +7,18 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var numerals = {
|
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]],
|
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,82,82,90,73,90,65,82,65,27,59,27,51,19,51,9,59,1]],
|
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,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]],
|
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,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]],
|
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,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]],
|
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,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]],
|
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,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]],
|
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,15,90,9,90,1,82,1,76,54,23,9,23,1,15,1,9,9,1]],
|
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,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]],
|
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,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]],
|
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 _hCol = ["#ff5555","#ffff00","#FF9901","#2F00FF"];
|
||||||
var _mCol = ["#55ff55","#ffffff","#00EFEF","#FFBF00"];
|
var _mCol = ["#55ff55","#ffffff","#00EFEF","#FFBF00"];
|
||||||
var _rCol = 0;
|
var _rCol = 0;
|
||||||
|
|
@ -29,25 +30,26 @@ function translate(tx, ty, p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function fill(poly){
|
function fill(poly){
|
||||||
return g.fillPoly(poly);
|
return g.fillPoly(poly,true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function frame(poly){
|
function frame(poly){
|
||||||
return g.drawPoly(poly);
|
return g.drawPoly(poly,true);
|
||||||
}
|
}
|
||||||
|
|
||||||
let settings = require('Storage').readJSON('numerals.json',1);
|
let settings = require('Storage').readJSON('numerals.json',1);
|
||||||
if (!settings) {
|
if (!settings) {
|
||||||
settings = {
|
settings = {
|
||||||
color:0,
|
color:0,
|
||||||
drawMode: "fill"
|
drawMode:"fill",
|
||||||
|
menuButton:24
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawNum(num,col,x,y,func){
|
function drawNum(num,col,x,y,func){
|
||||||
g.setColor(col);
|
g.setColor(col);
|
||||||
let tx = x*100+35;
|
let tx = x*100+25;
|
||||||
let ty = y*100+35;
|
let ty = y*104+32;
|
||||||
for (let i=0;i<numerals[num].length;i++){
|
for (let i=0;i<numerals[num].length;i++){
|
||||||
if (i>0) g.setColor((func==fill)?"#000000":col);
|
if (i>0) g.setColor((func==fill)?"#000000":col);
|
||||||
func(translate(tx,ty,numerals[num][i]));
|
func(translate(tx,ty,numerals[num][i]));
|
||||||
|
|
@ -56,8 +58,8 @@ function drawNum(num,col,x,y,func){
|
||||||
|
|
||||||
function draw(drawMode){
|
function draw(drawMode){
|
||||||
let d = new Date();
|
let d = new Date();
|
||||||
let h1 = Math.floor(d.getHours()/10);
|
let h1 = Math.floor((_12hour?d.getHours()%12:d.getHours())/10);
|
||||||
let h2 = d.getHours()%10;
|
let h2 = (_12hour?d.getHours()%12:d.getHours())%10;
|
||||||
let m1 = Math.floor(d.getMinutes()/10);
|
let m1 = Math.floor(d.getMinutes()/10);
|
||||||
let m2 = d.getMinutes()%10;
|
let m2 = d.getMinutes()%10;
|
||||||
g.clearRect(0,24,240,240);
|
g.clearRect(0,24,240,240);
|
||||||
|
|
@ -70,7 +72,7 @@ function draw(drawMode){
|
||||||
Bangle.setLCDMode();
|
Bangle.setLCDMode();
|
||||||
|
|
||||||
clearWatch();
|
clearWatch();
|
||||||
setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"});
|
setWatch(Bangle.showLauncher, settings.menuButton, {repeat:false,edge:"falling"});
|
||||||
|
|
||||||
g.clear();
|
g.clear();
|
||||||
clearInterval();
|
clearInterval();
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,16 @@
|
||||||
function resetSettings() {
|
function resetSettings() {
|
||||||
numeralsSettings = {
|
numeralsSettings = {
|
||||||
color:0,
|
color:0,
|
||||||
drawMode: "fill"
|
drawMode:"fill",
|
||||||
|
menuButton:22
|
||||||
};
|
};
|
||||||
updateSettings();
|
updateSettings();
|
||||||
}
|
}
|
||||||
let numeralsSettings = storage.readJSON('numerals.json',1);
|
let numeralsSettings = storage.readJSON('numerals.json',1);
|
||||||
if (!numeralsSettings) resetSettings();
|
if (!numeralsSettings) resetSettings();
|
||||||
let dm = ["fill","frame"];
|
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={
|
var menu={
|
||||||
"" : { "title":"Numerals"},
|
"" : { "title":"Numerals"},
|
||||||
"Colors": {
|
"Colors": {
|
||||||
|
|
@ -27,6 +29,12 @@
|
||||||
format: v=>dm[v],
|
format: v=>dm[v],
|
||||||
onchange: v=> { numeralsSettings.drawMode=dm[v]; updateSettings();}
|
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
|
"< back": back
|
||||||
};
|
};
|
||||||
E.showMenu(menu);
|
E.showMenu(menu);
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,4 @@
|
||||||
Fixed bug from 0.01 where BN1 (reset) could clear the lap log when timer is running
|
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.04: Changed save file filename, add interface.html to allow laps to be loaded
|
||||||
0.05: Added widgets
|
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
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,12 @@ function getLapTimes() {
|
||||||
<div class="columns">\n`;
|
<div class="columns">\n`;
|
||||||
lapData.forEach((lap,lapIndex) => {
|
lapData.forEach((lap,lapIndex) => {
|
||||||
lap.date = lap.n.substr(7,16).replace("_"," ");
|
lap.date = lap.n.substr(7,16).replace("_"," ");
|
||||||
|
lap.elapsed = lap.d.shift(); // remove first item
|
||||||
html += `
|
html += `
|
||||||
<div class="column col-12">
|
<div class="column col-12">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="card-title h5">${lap.date}</div>
|
<div class="card-title h5">${lap.date}</div>
|
||||||
<div class="card-subtitle text-gray">${lap.d.length} Laps</div>
|
<div class="card-subtitle text-gray">${lap.d.length} Laps, total time ${lap.elapsed}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<table class="table table-striped table-hover">
|
<table class="table table-striped table-hover">
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
|
var tTotal = Date.now();
|
||||||
var tStart = Date.now();
|
var tStart = Date.now();
|
||||||
var tCurrent = Date.now();
|
var tCurrent = Date.now();
|
||||||
var started = false;
|
var started = false;
|
||||||
var timeY = 60;
|
var timeY = 45;
|
||||||
var hsXPos = 0;
|
var hsXPos = 0;
|
||||||
|
var TtimeY = 75;
|
||||||
|
var ThsXPos = 0;
|
||||||
var lapTimes = [];
|
var lapTimes = [];
|
||||||
var displayInterval;
|
var displayInterval;
|
||||||
|
|
||||||
|
|
@ -12,6 +15,7 @@ function timeToText(t) {
|
||||||
var hs = Math.floor(t/10)%100;
|
var hs = Math.floor(t/10)%100;
|
||||||
return mins+":"+("0"+secs).substr(-2)+"."+("0"+hs).substr(-2);
|
return mins+":"+("0"+secs).substr(-2)+"."+("0"+hs).substr(-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateLabels() {
|
function updateLabels() {
|
||||||
g.reset(1);
|
g.reset(1);
|
||||||
g.clearRect(0,23,g.getWidth()-1,g.getHeight()-24);
|
g.clearRect(0,23,g.getWidth()-1,g.getHeight()-24);
|
||||||
|
|
@ -23,36 +27,54 @@ function updateLabels() {
|
||||||
g.setFont("6x8",1);
|
g.setFont("6x8",1);
|
||||||
g.setFontAlign(-1,-1);
|
g.setFontAlign(-1,-1);
|
||||||
for (var i in lapTimes) {
|
for (var i in lapTimes) {
|
||||||
if (i<16)
|
if (i<15)
|
||||||
{g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),35,timeY + 30 + i*8);}
|
{g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),35,timeY + 40 + i*8);}
|
||||||
else if (i<32)
|
else if (i<30)
|
||||||
{g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),125,timeY + 30 + (i-16)*8);}
|
{g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),125,timeY + 40 + (i-15)*8);}
|
||||||
}
|
}
|
||||||
drawsecs();
|
drawsecs();
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawsecs() {
|
function drawsecs() {
|
||||||
var t = tCurrent-tStart;
|
var t = tCurrent-tStart;
|
||||||
g.reset(1);
|
var Tt = tCurrent-tTotal;
|
||||||
g.setFont("Vector",48);
|
|
||||||
g.setFontAlign(0,0);
|
|
||||||
var secs = Math.floor(t/1000)%60;
|
var secs = Math.floor(t/1000)%60;
|
||||||
var mins = Math.floor(t/60000);
|
var mins = Math.floor(t/60000);
|
||||||
var txt = mins+":"+("0"+secs).substr(-2);
|
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;
|
var x = 100;
|
||||||
g.clearRect(0,timeY-26,200,timeY+26);
|
var Tx = 125;
|
||||||
g.drawString(txt,x,timeY);
|
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;
|
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();
|
drawms();
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawms() {
|
function drawms() {
|
||||||
var t = tCurrent-tStart;
|
var t = tCurrent-tStart;
|
||||||
var hs = Math.floor(t/10)%100;
|
var hs = Math.floor(t/10)%100;
|
||||||
|
var Tt = tCurrent-tTotal;
|
||||||
|
var Ths = Math.floor(Tt/10)%100;
|
||||||
g.setFontAlign(-1,0);
|
g.setFontAlign(-1,0);
|
||||||
g.setFont("6x8",2);
|
g.setFont("6x8",2);
|
||||||
g.clearRect(hsXPos,timeY,220,timeY+20);
|
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() {
|
function getLapTimesArray() {
|
||||||
|
lapTimes.push(tCurrent-tTotal);
|
||||||
return lapTimes.map(timeToText).reverse();
|
return lapTimes.map(timeToText).reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,6 +83,7 @@ setWatch(function() { // Start/stop
|
||||||
Bangle.beep();
|
Bangle.beep();
|
||||||
if (started)
|
if (started)
|
||||||
tStart = Date.now()+tStart-tCurrent;
|
tStart = Date.now()+tStart-tCurrent;
|
||||||
|
tTotal = Date.now()+tTotal-tCurrent;
|
||||||
tCurrent = Date.now();
|
tCurrent = Date.now();
|
||||||
if (displayInterval) {
|
if (displayInterval) {
|
||||||
clearInterval(displayInterval);
|
clearInterval(displayInterval);
|
||||||
|
|
@ -77,28 +100,32 @@ setWatch(function() { // Start/stop
|
||||||
drawms();
|
drawms();
|
||||||
}, 20);
|
}, 20);
|
||||||
}, BTN2, {repeat:true});
|
}, BTN2, {repeat:true});
|
||||||
|
|
||||||
setWatch(function() { // Lap
|
setWatch(function() { // Lap
|
||||||
Bangle.beep();
|
Bangle.beep();
|
||||||
if (started) {
|
if (started) {
|
||||||
tCurrent = Date.now();
|
tCurrent = Date.now();
|
||||||
lapTimes.unshift(tCurrent-tStart);
|
lapTimes.unshift(tCurrent-tStart);
|
||||||
}
|
}
|
||||||
tStart = tCurrent;
|
|
||||||
if (!started) { // save
|
if (!started) { // save
|
||||||
var timenow= Date();
|
|
||||||
var filename = "swatch-"+(new Date()).toISOString().substr(0,16).replace("T","_")+".json";
|
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
|
// this maxes out the 28 char maximum
|
||||||
require("Storage").writeJSON(filename, getLapTimesArray());
|
require("Storage").writeJSON(filename, getLapTimesArray());
|
||||||
|
tStart = tCurrent = tTotal = Date.now();
|
||||||
|
lapTimes = [];
|
||||||
E.showMessage("Laps Saved","Stopwatch");
|
E.showMessage("Laps Saved","Stopwatch");
|
||||||
setTimeout(updateLabels, 1000);
|
setTimeout(updateLabels, 1000);
|
||||||
} else {
|
} else {
|
||||||
|
tStart = tCurrent;
|
||||||
updateLabels();
|
updateLabels();
|
||||||
}
|
}
|
||||||
}, BTN1, {repeat:true});
|
}, BTN1, {repeat:true});
|
||||||
setWatch(function() { // Reset
|
setWatch(function() { // Reset
|
||||||
if (!started) {
|
if (!started) {
|
||||||
Bangle.beep();
|
Bangle.beep();
|
||||||
tStart = tCurrent = Date.now();
|
tStart = tCurrent = tTotal = Date.now();
|
||||||
lapTimes = [];
|
lapTimes = [];
|
||||||
}
|
}
|
||||||
updateLabels();
|
updateLabels();
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,4 @@
|
||||||
0.03: Close launcher when lcd turn off
|
0.03: Close launcher when lcd turn off
|
||||||
0.04: Complete rewrite to add animation and loop ( issue #210 )
|
0.04: Complete rewrite to add animation and loop ( issue #210 )
|
||||||
0.05: Improve perf
|
0.05: Improve perf
|
||||||
|
0.06: Only store relevant app data (saves RAM when many apps)
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ g.flip();
|
||||||
const Storage = require("Storage");
|
const Storage = require("Storage");
|
||||||
|
|
||||||
function getApps(){
|
function getApps(){
|
||||||
return Storage.list(/\.info$/).filter(app => app.endsWith('.info')).map(app => Storage.readJSON(app,1) || { name: "DEAD: "+app.substr(1) })
|
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.type=="app" || app.type=="clock" || !app.type)
|
.filter(app=>app && (app.type=="app" || app.type=="clock" || !app.type))
|
||||||
.sort((a,b)=>{
|
.sort((a,b)=>{
|
||||||
var n=(0|a.sortorder)-(0|b.sortorder);
|
var n=(0|a.sortorder)-(0|b.sortorder);
|
||||||
if (n) return n; // do sortorder first
|
if (n) return n; // do sortorder first
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue