mirror of https://github.com/espruino/BangleApps
Add page to export files from Stopwatch, save files in better format and with better filename
parent
9b918055da
commit
f66aab5823
|
@ -392,7 +392,8 @@
|
||||||
{ "id": "swatch",
|
{ "id": "swatch",
|
||||||
"name": "Stopwatch",
|
"name": "Stopwatch",
|
||||||
"icon": "stopwatch.png",
|
"icon": "stopwatch.png",
|
||||||
"version":"0.03",
|
"version":"0.04",
|
||||||
|
"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",
|
||||||
"allow_emulator":true,
|
"allow_emulator":true,
|
||||||
|
|
|
@ -11,17 +11,7 @@ var domRecords = document.getElementById("records");
|
||||||
|
|
||||||
function saveRecord(record,name) {
|
function saveRecord(record,name) {
|
||||||
var csv = `${record.map(rec=>[rec.time, rec.bpm, rec.confidence].join(",")).join("\n")}`;
|
var csv = `${record.map(rec=>[rec.time, rec.bpm, rec.confidence].join(",")).join("\n")}`;
|
||||||
var a = document.createElement("a"),
|
Util.saveCSV(name, csv);
|
||||||
file = new Blob([csv], {type: "Comma-separated value file"});
|
|
||||||
var url = URL.createObjectURL(file);
|
|
||||||
a.href = url;
|
|
||||||
a.download = name+".csv";
|
|
||||||
document.body.appendChild(a);
|
|
||||||
a.click();
|
|
||||||
setTimeout(function() {
|
|
||||||
document.body.removeChild(a);
|
|
||||||
window.URL.revokeObjectURL(url);
|
|
||||||
}, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,3 +3,4 @@
|
||||||
Lap log now scrolls into 2nd column after 18th entry, able to display 36 entries before going off screen
|
Lap log now scrolls into 2nd column after 18th entry, able to display 36 entries before going off screen
|
||||||
0.03: Added ability to save Lap log as a date named JSON file into memory
|
0.03: Added ability to save Lap log as a date named JSON file into memory
|
||||||
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,0 +1,90 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="../../css/spectre.min.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="records"></div>
|
||||||
|
|
||||||
|
<script src="../../lib/interface.js"></script>
|
||||||
|
<script>
|
||||||
|
var domRecords = document.getElementById("records");
|
||||||
|
|
||||||
|
function getLapTimes() {
|
||||||
|
Util.showModal("Loading Lap Times...");
|
||||||
|
domRecords.innerHTML = "";
|
||||||
|
Puck.eval('require("Storage").list(/^swatch.*\.json/).map(fn=>({n:fn,d:require("Storage").readJSON(fn,1)}))',lapData=>{
|
||||||
|
var html = `<div class="container">
|
||||||
|
<div class="columns">\n`;
|
||||||
|
lapData.forEach((lap,lapIndex) => {
|
||||||
|
lap.date = lap.n.substr(7,16).replace("_"," ");
|
||||||
|
html += `
|
||||||
|
<div class="column col-12">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title h5">${lap.date}</div>
|
||||||
|
<div class="card-subtitle text-gray">${lap.d.length} Laps</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>lap</th>
|
||||||
|
<th>time</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
${ lap.d.map((d,n)=>`<tr><td>${n+1}</td><td>${d}</td></tr>`).join("\n") }
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<button class="btn btn-primary" idx="${lapIndex}" task="download">Download</button>
|
||||||
|
<button class="btn btn-default" idx="${lapIndex}" task="delete">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
if (lapData.length==0) {
|
||||||
|
html += `
|
||||||
|
<div class="column col-12">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title h5">No record</div>
|
||||||
|
<div class="card-subtitle text-gray">No laps recorded</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
html += `
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
domRecords.innerHTML = html;
|
||||||
|
Util.hideModal();
|
||||||
|
var buttons = domRecords.querySelectorAll("button");
|
||||||
|
for (var i=0;i<buttons.length;i++) {
|
||||||
|
buttons[i].addEventListener("click",event => {
|
||||||
|
var button = event.currentTarget;
|
||||||
|
var lapIndex = parseInt(button.getAttribute("idx"));
|
||||||
|
var lap = lapData[lapIndex];
|
||||||
|
if (!lap) throw new Error("Invalid index!");
|
||||||
|
var task = button.getAttribute("task");
|
||||||
|
if (task=="delete") {
|
||||||
|
Util.showModal("Deleting lap time...");
|
||||||
|
Util.eraseStorage(lap.n,()=>{
|
||||||
|
Util.hideModal();
|
||||||
|
getLapTimes();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (task=="download") {
|
||||||
|
Util.saveCSV(lap.n.slice(0,-5)+".csv", lap.d.map((d,n)=>[n+1,d].join(",")).join("\n"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function onInit() {
|
||||||
|
getLapTimes();
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -4,7 +4,6 @@ var started = false;
|
||||||
var timeY = 60;
|
var timeY = 60;
|
||||||
var hsXPos = 0;
|
var hsXPos = 0;
|
||||||
var lapTimes = [];
|
var lapTimes = [];
|
||||||
var saveTimes = [];
|
|
||||||
var displayInterval;
|
var displayInterval;
|
||||||
|
|
||||||
function timeToText(t) {
|
function timeToText(t) {
|
||||||
|
@ -51,10 +50,8 @@ function drawms() {
|
||||||
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"+hs).substr(-2),hsXPos,timeY+10);
|
||||||
}
|
}
|
||||||
function saveconvert() {
|
function getLapTimesArray() {
|
||||||
for (var v in lapTimes){
|
return lapTimes.map(timeToText).reverse();
|
||||||
saveTimes[v]=v+1+"-"+timeToText(lapTimes[(lapTimes.length-1)-v]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setWatch(function() { // Start/stop
|
setWatch(function() { // Start/stop
|
||||||
|
@ -80,16 +77,21 @@ setWatch(function() { // Start/stop
|
||||||
}, BTN2, {repeat:true});
|
}, BTN2, {repeat:true});
|
||||||
setWatch(function() { // Lap
|
setWatch(function() { // Lap
|
||||||
Bangle.beep();
|
Bangle.beep();
|
||||||
if (started) tCurrent = Date.now();
|
if (started) {
|
||||||
|
tCurrent = Date.now();
|
||||||
lapTimes.unshift(tCurrent-tStart);
|
lapTimes.unshift(tCurrent-tStart);
|
||||||
tStart = tCurrent;
|
|
||||||
if (!started)
|
|
||||||
{
|
|
||||||
var timenow= Date();
|
|
||||||
saveconvert();
|
|
||||||
require("Storage").writeJSON("StpWch-"+timenow.toString(), saveTimes);
|
|
||||||
}
|
}
|
||||||
|
tStart = tCurrent;
|
||||||
|
if (!started) { // save
|
||||||
|
var timenow= Date();
|
||||||
|
var filename = "swatch-"+(new Date()).toISOString().substr(0,16).replace("T","_")+".json";
|
||||||
|
// this maxes out the 28 char maximum
|
||||||
|
require("Storage").writeJSON(filename, getLapTimesArray());
|
||||||
|
E.showMessage("Laps Saved","Stopwatch");
|
||||||
|
setTimeout(updateLabels, 1000);
|
||||||
|
} else {
|
||||||
updateLabels();
|
updateLabels();
|
||||||
|
}
|
||||||
}, BTN1, {repeat:true});
|
}, BTN1, {repeat:true});
|
||||||
setWatch(function() { // Reset
|
setWatch(function() { // Reset
|
||||||
if (!started) {
|
if (!started) {
|
||||||
|
|
|
@ -39,7 +39,10 @@ var Util = {
|
||||||
window.postMessage({type:"readstoragefile",data:filename,id:__id});
|
window.postMessage({type:"readstoragefile",data:filename,id:__id});
|
||||||
},
|
},
|
||||||
eraseStorageFile : function(filename,callback) {
|
eraseStorageFile : function(filename,callback) {
|
||||||
Puck.write(`\x10require("Storage").open(${JSON.stringify(filename)}","r").erase()\n`,callback);
|
Puck.write(`\x10require("Storage").open(${JSON.stringify(filename)},"r").erase()\n`,callback);
|
||||||
|
},
|
||||||
|
eraseStorage : function(filename,callback) {
|
||||||
|
Puck.write(`\x10require("Storage").erase(${JSON.stringify(filename)})\n`,callback);
|
||||||
},
|
},
|
||||||
showModal : function(title) {
|
showModal : function(title) {
|
||||||
if (!Util.domModal) {
|
if (!Util.domModal) {
|
||||||
|
@ -66,6 +69,19 @@ var Util = {
|
||||||
hideModal : function() {
|
hideModal : function() {
|
||||||
if (!Util.domModal) return;
|
if (!Util.domModal) return;
|
||||||
Util.domModal.classList.remove("active");
|
Util.domModal.classList.remove("active");
|
||||||
|
},
|
||||||
|
saveCSV : function(filename, csvData) {
|
||||||
|
var a = document.createElement("a"),
|
||||||
|
file = new Blob([csvData], {type: "Comma-separated value file"});
|
||||||
|
var url = URL.createObjectURL(file);
|
||||||
|
a.href = url;
|
||||||
|
a.download = filename+".csv";
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
setTimeout(function() {
|
||||||
|
document.body.removeChild(a);
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
}, 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
window.addEventListener("message", function(event) {
|
window.addEventListener("message", function(event) {
|
||||||
|
|
Loading…
Reference in New Issue