Added showModal/hideModal utility functions
Added readStorageFile/eraseStorageFile to handle efficiently downloading large files (fix #119)master
parent
04f8cbcd13
commit
dd0e3c89d1
|
|
@ -5,32 +5,9 @@
|
||||||
<body>
|
<body>
|
||||||
<div id="tracks"></div>
|
<div id="tracks"></div>
|
||||||
|
|
||||||
<div class="modal active" id="status-modal">
|
|
||||||
<div class="modal-overlay"></div>
|
|
||||||
<div class="modal-container">
|
|
||||||
<div class="modal-header">
|
|
||||||
<div class="modal-title h5">Please wait</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="content">
|
|
||||||
Loading...
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="../../lib/interface.js"></script>
|
<script src="../../lib/interface.js"></script>
|
||||||
<script>
|
<script>
|
||||||
var domTracks = document.getElementById("tracks");
|
var domTracks = document.getElementById("tracks");
|
||||||
var domModal = document.getElementById("status-modal");
|
|
||||||
|
|
||||||
function showModal(title) {
|
|
||||||
domModal.querySelector(".content").innerHTML = title;
|
|
||||||
domModal.classList.add("active");
|
|
||||||
}
|
|
||||||
function hideModal(title) {
|
|
||||||
domModal.classList.remove("active");
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveKML(track,title) {
|
function saveKML(track,title) {
|
||||||
var kml = `<?xml version="1.0" encoding="UTF-8"?>
|
var kml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
@ -107,19 +84,15 @@ function trackLineToObject(l, hasTrackNumber) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadTrack(trackid, callback) {
|
function downloadTrack(trackid, callback) {
|
||||||
showModal("Downloading Track...");
|
Util.showModal("Downloading Track...");
|
||||||
Puck.write(`\x10(function() {
|
Util.readStorageFile(`.gpsrc${trackid.toString(36)}`,data=>{
|
||||||
var f = require("Storage").open(".gpsrc${trackid.toString(36)}","r");
|
Util.hideModal();
|
||||||
var l = f.readLine();
|
var track = data.trim().split("\n").map(l=>trackLineToObject(l,false));
|
||||||
while (l!==undefined) { Bluetooth.print(l); l = f.readLine(); }
|
|
||||||
})()\n`,tracklist=>{
|
|
||||||
hideModal();
|
|
||||||
var track = tracklist.trim().split("\n").map(l=>trackLineToObject(l,false));
|
|
||||||
callback(track);
|
callback(track);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function getTrackList() {
|
function getTrackList() {
|
||||||
showModal("Loading Tracks...");
|
Util.showModal("Loading Tracks...");
|
||||||
domTracks.innerHTML = "";
|
domTracks.innerHTML = "";
|
||||||
Puck.write(`\x10(function() {
|
Puck.write(`\x10(function() {
|
||||||
for (var n=0;n<36;n++) {
|
for (var n=0;n<36;n++) {
|
||||||
|
|
@ -171,7 +144,7 @@ function getTrackList() {
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
domTracks.innerHTML = html;
|
domTracks.innerHTML = html;
|
||||||
hideModal();
|
Util.hideModal();
|
||||||
var buttons = domTracks.querySelectorAll("button");
|
var buttons = domTracks.querySelectorAll("button");
|
||||||
for (var i=0;i<buttons.length;i++) {
|
for (var i=0;i<buttons.length;i++) {
|
||||||
buttons[i].addEventListener("click",event => {
|
buttons[i].addEventListener("click",event => {
|
||||||
|
|
@ -179,9 +152,9 @@ function getTrackList() {
|
||||||
var trackid = parseInt(button.getAttribute("trackid"));
|
var trackid = parseInt(button.getAttribute("trackid"));
|
||||||
var task = button.getAttribute("task");
|
var task = button.getAttribute("task");
|
||||||
if (task=="delete") {
|
if (task=="delete") {
|
||||||
showModal("Deleting Track...");
|
Util.showModal("Deleting Track...");
|
||||||
Puck.write(`\x10require("Storage").open(".gpsrc${trackid.toString(36)}","r").erase()\n`,()=>{
|
Util.eraseStorageFile(`.gpsrc${trackid.toString(36)}`,()=>{
|
||||||
hideModal();
|
Util.hideModal();
|
||||||
getTrackList();
|
getTrackList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,32 +5,9 @@
|
||||||
<body>
|
<body>
|
||||||
<div id="records"></div>
|
<div id="records"></div>
|
||||||
|
|
||||||
<div class="modal active" id="status-modal">
|
|
||||||
<div class="modal-overlay"></div>
|
|
||||||
<div class="modal-container">
|
|
||||||
<div class="modal-header">
|
|
||||||
<div class="modal-name h5">Please wait</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="content">
|
|
||||||
Loading...
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="../../lib/interface.js"></script>
|
<script src="../../lib/interface.js"></script>
|
||||||
<script>
|
<script>
|
||||||
var domRecords = document.getElementById("records");
|
var domRecords = document.getElementById("records");
|
||||||
var domModal = document.getElementById("status-modal");
|
|
||||||
|
|
||||||
function showModal(name) {
|
|
||||||
domModal.querySelector(".content").innerHTML = name;
|
|
||||||
domModal.classList.add("active");
|
|
||||||
}
|
|
||||||
function hideModal(name) {
|
|
||||||
domModal.classList.remove("active");
|
|
||||||
}
|
|
||||||
|
|
||||||
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")}`;
|
||||||
|
|
@ -62,20 +39,16 @@ function recordLineToObject(l, hasRecordNbr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadRecord(recordNbr, callback) {
|
function downloadRecord(recordNbr, callback) {
|
||||||
showModal("Downloading heart rate record...");
|
Util.showModal("Downloading heart rate record...");
|
||||||
Puck.write(`\x10(function() {
|
Util.readStorageFile(`.heart${recordNbr.toString(36)}`,data=>{
|
||||||
var f = require("Storage").open(".heart${recordNbr.toString(36)}","r");
|
Util.hideModal();
|
||||||
var l = f.readLine();
|
var record = data.trim().split("\n").map(l=>recordLineToObject(l,false));
|
||||||
while (l!==undefined) { Bluetooth.print(l); l = f.readLine(); }
|
|
||||||
})()\n`,recordList=>{
|
|
||||||
hideModal();
|
|
||||||
var record = recordList.trim().split("\n").map(l=>recordLineToObject(l,false));
|
|
||||||
callback(record);
|
callback(record);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRecordList() {
|
function getRecordList() {
|
||||||
showModal("Loading heart rate records...");
|
Util.showModal("Loading heart rate records...");
|
||||||
domRecords.innerHTML = "";
|
domRecords.innerHTML = "";
|
||||||
Puck.write(`\x10(function() {
|
Puck.write(`\x10(function() {
|
||||||
for (var n=0;n<36;n++) {
|
for (var n=0;n<36;n++) {
|
||||||
|
|
@ -118,7 +91,7 @@ function getRecordList() {
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
domRecords.innerHTML = html;
|
domRecords.innerHTML = html;
|
||||||
hideModal();
|
Util.hideModal();
|
||||||
var buttons = domRecords.querySelectorAll("button");
|
var buttons = domRecords.querySelectorAll("button");
|
||||||
for (var i=0;i<buttons.length;i++) {
|
for (var i=0;i<buttons.length;i++) {
|
||||||
buttons[i].addEventListener("click",event => {
|
buttons[i].addEventListener("click",event => {
|
||||||
|
|
@ -126,9 +99,9 @@ function getRecordList() {
|
||||||
var recordNbr = parseInt(button.getAttribute("recordNbr"));
|
var recordNbr = parseInt(button.getAttribute("recordNbr"));
|
||||||
var task = button.getAttribute("task");
|
var task = button.getAttribute("task");
|
||||||
if (task=="delete") {
|
if (task=="delete") {
|
||||||
showModal("Deleting record...");
|
Util.showModal("Deleting record...");
|
||||||
Puck.write(`\x10require("Storage").open(".heart${recordNbr.toString(36)}","r").erase()\n`,()=>{
|
Util.eraseStorageFile(`.heart${recordNbr.toString(36)}`,()=>{
|
||||||
hideModal();
|
Util.hideModal();
|
||||||
getRecordList();
|
getRecordList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
45
js/comms.js
45
js/comms.js
|
|
@ -147,5 +147,50 @@ readFile : (file) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
readStorageFile : (filename) => { // StorageFiles are different to normal storage entries
|
||||||
|
return new Promise((resolve,reject) => {
|
||||||
|
// Use "\xFF" to signal end of file (can't occur in files anyway)
|
||||||
|
var fileContent = "";
|
||||||
|
var fileSize = undefined;
|
||||||
|
var connection = Puck.getConnection();
|
||||||
|
connection.received = "";
|
||||||
|
connection.cb = function(d) {
|
||||||
|
var finished = false;
|
||||||
|
var eofIndex = d.indexOf("\xFF");
|
||||||
|
if (eofIndex>=0) {
|
||||||
|
finished = true;
|
||||||
|
d = d.substr(0,eofIndex);
|
||||||
|
}
|
||||||
|
fileContent += d;
|
||||||
|
if (fileSize === undefined) {
|
||||||
|
var newLineIdx = fileContent.indexOf("\n");
|
||||||
|
if (newLineIdx>=0) {
|
||||||
|
fileSize = parseInt(fileContent.substr(0,newLineIdx));
|
||||||
|
console.log("File size is "+fileSize);
|
||||||
|
fileContent = fileContent.substr(newLineIdx+1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showProgress(undefined,100*fileContent.length / (fileSize||1000000));
|
||||||
|
}
|
||||||
|
if (finished) {
|
||||||
|
hideProgress();
|
||||||
|
connection.received = "";
|
||||||
|
connection.cb = undefined;
|
||||||
|
resolve(fileContent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(`Reading StorageFile ${JSON.stringify(filename)}`);
|
||||||
|
connection.write(`\x03\x10(function() {
|
||||||
|
var f = require("Storage").open(${JSON.stringify(filename)},"r");
|
||||||
|
Bluetooth.println(f.getLength());
|
||||||
|
var l = f.readLine();
|
||||||
|
while (l!==undefined) { Bluetooth.print(l); l = f.readLine(); }
|
||||||
|
Bluetooth.print("\xFF");
|
||||||
|
})()\n`,() => {
|
||||||
|
showProgress(`Reading ${JSON.stringify(filename)}`,0);
|
||||||
|
console.log(`StorageFile read started...`);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -229,6 +229,14 @@ function handleAppInterface(app) {
|
||||||
id : msg.id
|
id : msg.id
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
} else if (msg.type=="readstoragefile") {
|
||||||
|
Comms.readStorageFile(msg.data/*filename*/).then(function(result) {
|
||||||
|
iwin.postMessage({
|
||||||
|
type : "readstoragefilersp",
|
||||||
|
data : result,
|
||||||
|
id : msg.id
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, false);
|
}, false);
|
||||||
iwin.postMessage({type:"init"});
|
iwin.postMessage({type:"init"});
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,21 @@ be used from within BangleApps
|
||||||
|
|
||||||
See: README.md / `apps.json`: `interface` element
|
See: README.md / `apps.json`: `interface` element
|
||||||
|
|
||||||
This exposes a 'Puck' object like the puck.js library,
|
This exposes a 'Puck' object (a simple version of
|
||||||
and calls `onInit` when it's ready. `Puck` can be used
|
https://github.com/espruino/EspruinoWebTools/blob/master/puck.js)
|
||||||
for sending/receiving data to the correctly connected
|
and calls `onInit` when it's ready. `Puck` can be used for
|
||||||
|
sending/receiving data to the correctly connected
|
||||||
device with Puck.eval/write.
|
device with Puck.eval/write.
|
||||||
|
|
||||||
|
Puck.write(data,callback)
|
||||||
|
Puck.eval(data,callback)
|
||||||
|
|
||||||
|
There is also:
|
||||||
|
|
||||||
|
Util.readStorageFile(filename,callback)
|
||||||
|
Util.eraseStorageFile(filename,callback)
|
||||||
|
Util.showModal(title)
|
||||||
|
Util.hideModal()
|
||||||
*/
|
*/
|
||||||
var __id = 0, __idlookup = [];
|
var __id = 0, __idlookup = [];
|
||||||
var Puck = {
|
var Puck = {
|
||||||
|
|
@ -20,11 +31,48 @@ var Puck = {
|
||||||
window.postMessage({type:"write",data:data,id:__id});
|
window.postMessage({type:"write",data:data,id:__id});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var Util = {
|
||||||
|
readStorageFile : function(filename,callback) {
|
||||||
|
__id++;
|
||||||
|
__idlookup[__id] = callback;
|
||||||
|
window.postMessage({type:"readstoragefile",data:filename,id:__id});
|
||||||
|
},
|
||||||
|
eraseStorageFile : function(filename,callback) {
|
||||||
|
Puck.write(`\x10require("Storage").open(${JSON.stringify(filename)}","r").erase()\n`,callback);
|
||||||
|
},
|
||||||
|
showModal : function(title) {
|
||||||
|
if (!Util.domModal) {
|
||||||
|
Util.domModal = document.createElement('div');
|
||||||
|
Util.domModal.id = "status-modal";
|
||||||
|
Util.domModal.classList.add("modal");
|
||||||
|
Util.domModal.classList.add("active");
|
||||||
|
Util.domModal.innerHTML = `<div class="modal-overlay"></div>
|
||||||
|
<div class="modal-container">
|
||||||
|
<div class="modal-header">
|
||||||
|
<div class="modal-title h5">Please wait</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="content">
|
||||||
|
Loading...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
document.body.appendChild(Util.domModal);
|
||||||
|
}
|
||||||
|
Util.domModal.querySelector(".content").innerHTML = title;
|
||||||
|
Util.domModal.classList.add("active");
|
||||||
|
},
|
||||||
|
hideModal : function() {
|
||||||
|
if (!Util.domModal) return;
|
||||||
|
Util.domModal.classList.remove("active");
|
||||||
|
}
|
||||||
|
};
|
||||||
window.addEventListener("message", function(event) {
|
window.addEventListener("message", function(event) {
|
||||||
var msg = event.data;
|
var msg = event.data;
|
||||||
if (msg.type=="init") {
|
if (msg.type=="init") {
|
||||||
onInit();
|
onInit();
|
||||||
} else if (msg.type=="evalrsp" || msg.type=="writersp") {
|
} else if (msg.type=="evalrsp" || msg.type=="writersp"|| msg.type=="readstoragefilersp") {
|
||||||
var cb = __idlookup[msg.id];
|
var cb = __idlookup[msg.id];
|
||||||
delete __idlookup[msg.id];
|
delete __idlookup[msg.id];
|
||||||
cb(msg.data);
|
cb(msg.data);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue