forked from FOSS/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",
|
||||
"name": "Stopwatch",
|
||||
"icon": "stopwatch.png",
|
||||
"version":"0.03",
|
||||
"version":"0.04",
|
||||
"interface": "interface.html",
|
||||
"description": "Simple stopwatch with Lap Time logging to a JSON file",
|
||||
"tags": "health",
|
||||
"allow_emulator":true,
|
||||
|
|
|
@ -11,17 +11,7 @@ var domRecords = document.getElementById("records");
|
|||
|
||||
function saveRecord(record,name) {
|
||||
var csv = `${record.map(rec=>[rec.time, rec.bpm, rec.confidence].join(",")).join("\n")}`;
|
||||
var a = document.createElement("a"),
|
||||
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);
|
||||
Util.saveCSV(name, csv);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
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
|
||||
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 hsXPos = 0;
|
||||
var lapTimes = [];
|
||||
var saveTimes = [];
|
||||
var displayInterval;
|
||||
|
||||
function timeToText(t) {
|
||||
|
@ -25,7 +24,7 @@ function updateLabels() {
|
|||
for (var i in lapTimes) {
|
||||
if (i<18)
|
||||
{g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),35,timeY + 30 + i*8);}
|
||||
else
|
||||
else
|
||||
{g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),125,timeY + 30 + (i-18)*8);}
|
||||
}
|
||||
drawsecs();
|
||||
|
@ -51,10 +50,8 @@ function drawms() {
|
|||
g.clearRect(hsXPos,timeY,220,timeY+20);
|
||||
g.drawString("."+("0"+hs).substr(-2),hsXPos,timeY+10);
|
||||
}
|
||||
function saveconvert() {
|
||||
for (var v in lapTimes){
|
||||
saveTimes[v]=v+1+"-"+timeToText(lapTimes[(lapTimes.length-1)-v]);
|
||||
}
|
||||
function getLapTimesArray() {
|
||||
return lapTimes.map(timeToText).reverse();
|
||||
}
|
||||
|
||||
setWatch(function() { // Start/stop
|
||||
|
@ -80,16 +77,21 @@ setWatch(function() { // Start/stop
|
|||
}, BTN2, {repeat:true});
|
||||
setWatch(function() { // Lap
|
||||
Bangle.beep();
|
||||
if (started) tCurrent = Date.now();
|
||||
lapTimes.unshift(tCurrent-tStart);
|
||||
tStart = tCurrent;
|
||||
if (!started)
|
||||
{
|
||||
var timenow= Date();
|
||||
saveconvert();
|
||||
require("Storage").writeJSON("StpWch-"+timenow.toString(), saveTimes);
|
||||
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";
|
||||
// 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});
|
||||
setWatch(function() { // Reset
|
||||
if (!started) {
|
||||
|
|
|
@ -39,7 +39,10 @@ var Util = {
|
|||
window.postMessage({type:"readstoragefile",data:filename,id:__id});
|
||||
},
|
||||
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) {
|
||||
if (!Util.domModal) {
|
||||
|
@ -66,6 +69,19 @@ var Util = {
|
|||
hideModal : function() {
|
||||
if (!Util.domModal) return;
|
||||
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) {
|
||||
|
|
Loading…
Reference in New Issue