Skip to content

Commit 7e7475b

Browse files
committed
Ensure we run transfers one after the other rather that potentially having them overlap if the user clicks around
#67
1 parent ef99424 commit 7e7475b

File tree

2 files changed

+126
-123
lines changed

2 files changed

+126
-123
lines changed

js/comms.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ const Comms = {
7676
return Puck.getConnection();
7777
}
7878
},
79-
supportsPacketUpload : () => (!SETTINGS.noPackets) && Comms.getConnection().espruinoSendFile && !Utils.versionLess(device.version,"2v25"),
79+
supportsPacketUpload : () => (!SETTINGS.noPackets) && Comms.getConnection().espruinoSendFile && device.version && !Utils.versionLess(device.version,"2v25"),
8080
// Faking EventEmitter
8181
handlers : {},
8282
on : function(id, callback) { // calling with callback=undefined will disable
@@ -321,9 +321,9 @@ const Comms = {
321321
then(() => Comms.write("\x10"+Comms.getProgressCmd()+"\n")).
322322
then(() => {
323323
doUploadFiles();
324-
}).catch(function() {
324+
}).catch((err) => {
325325
Progress.hide({sticky:true});
326-
return reject("");
326+
return reject(err);
327327
});
328328
}
329329
if (options.noReset) {
@@ -552,6 +552,8 @@ const Comms = {
552552
let timeout = 5;
553553
function handleResult(result,err) {
554554
console.log("<COMMS> removeAllApps: received "+JSON.stringify(result));
555+
if (!Comms.isConnected())
556+
return reject("Disconnected");
555557
if (result=="" && (timeout--)) {
556558
console.log("<COMMS> removeAllApps: no result - waiting some more ("+timeout+").");
557559
// send space and delete - so it's something, but it should just cancel out

js/index.js

Lines changed: 121 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,40 @@ let device = {
4141
};*/
4242
let LANGUAGE = undefined;
4343

44+
/** Ensure we run transfers one after the other rather that potentially having them overlap if the user clicks around
45+
https://github.com/espruino/EspruinoAppLoaderCore/issues/67 */
46+
let currentOperation = Promise.resolve();
47+
48+
/// Start an operation - calls back
49+
function startOperation(options, callback) {
50+
options = options||{};
51+
if (!options.name) throw new Error("Expecting a name");
52+
console.log(`=========== Queued Operation ${options.name}`);
53+
return new Promise(resolve => {
54+
currentOperation = currentOperation.then(() => {
55+
console.log(`=========== Starting Operation ${options.name}`);
56+
let promise = callback();
57+
if (!(promise instanceof Promise))
58+
throw new Error(`Operation ${options.name} didn't return a promise!`);
59+
return promise;
60+
}).then((result) => {
61+
console.log(`=========== Operation ${options.name} Complete`);
62+
Progress.hide({sticky:true});
63+
refreshMyApps();
64+
refreshLibrary();
65+
resolve(result);
66+
}, (err) => {
67+
console.error(`=========== ERROR during Operation ${options.name}`);
68+
showToast(`${options.name} failed, ${err}`,"error");
69+
Progress.hide({sticky:true});
70+
// remove loading indicator
71+
refreshMyApps();
72+
refreshLibrary();
73+
resolve();
74+
});
75+
});
76+
}
77+
4478
function appJSONLoadedHandler() {
4579
appJSON.forEach(app => {
4680
if (app.screenshots)
@@ -378,16 +412,10 @@ function handleCustomApp(appTemplate) {
378412
console.log("Received custom app", app);
379413
modal.remove();
380414

381-
getInstalledApps()
415+
startOperation({name:"Custom App Upload"}, () => getInstalledApps()
382416
.then(()=>checkDependencies(app))
383417
.then(()=>Comms.uploadApp(app,{device:device, language:LANGUAGE, noFinish: msg.options && msg.options.noFinish}))
384-
.then(()=>{
385-
Progress.hide({sticky:true});
386-
resolve();
387-
}).catch(err => {
388-
Progress.hide({sticky:true});
389-
reject('Upload failed, ' + err, 'error');
390-
});
418+
.then(resolve,reject));
391419
}
392420
}
393421
});
@@ -788,61 +816,43 @@ function uploadApp(app, options) {
788816
if (app.type == "defaultconfig" && !options.force) {
789817
return showPrompt("Default Configuration Install","<b>This will remove all apps and data from your Bangle</b> and will install a new set of apps. Please ensure you have backed up your Bangle first. Continue?",{yes:1,no:1},false)
790818
.then(() => showPrompt("Device Erasure","<b>Everything will be deleted from your Bangle.</b> Are you really sure?",{yes:1,no:1},false))
791-
.then(() => Comms.removeAllApps())
792-
.then(() => uploadApp(app, {force:true}))
793-
.catch(err => {
794-
showToast("Configuration install failed, "+err,"error");
795-
refreshMyApps();
796-
refreshLibrary();
797-
});
819+
.then(() => startOperation({name:"Remove All Apps"}, () => Comms.removeAllApps()))
820+
.then(() => uploadApp(app, {force:true}));
798821
}
799822

800-
return getInstalledApps().then(()=>{
823+
return startOperation({name:"App Upload"}, () => getInstalledApps().then(()=>{
801824
if (device.appsInstalled.some(i => i.id === app.id)) {
802825
return updateApp(app);
803826
}
804827
return checkDependencies(app)
805828
.then(()=>Comms.uploadApp(app,{device:device, language:LANGUAGE}))
806829
.then((appJSON) => {
807-
Progress.hide({ sticky: true });
808830
if (appJSON) {
809831
device.appsInstalled.push(appJSON);
810832
}
811833
showToast(app.name + ' Uploaded!', 'success');
812834
}).catch(err => {
813-
Progress.hide({ sticky: true });
814835
showToast('Upload failed, ' + err, 'error');
815-
}).finally(()=>{
816-
refreshMyApps();
817-
refreshLibrary();
818836
});
819-
}).catch(err => {
820-
showToast("App Upload failed, "+err,"error");
821-
// remove loading indicator
822-
refreshMyApps();
823-
refreshLibrary();
824-
});
837+
}));
825838
}
826839

827840
/** Prompt user and then remove app from the device */
828841
function removeApp(app) {
829842
return showPrompt("Delete","Really remove '"+app.name+"'?")
830-
.then(() => getInstalledApps())
831-
.then(()=> Comms.removeApp(device.appsInstalled.find(a => a.id === app.id))) // a = from appid.info, app = from apps.json
832-
.then(()=>{
833-
device.appsInstalled = device.appsInstalled.filter(a=>a.id!=app.id);
834-
showToast(app.name+" removed successfully","success");
835-
refreshMyApps();
836-
refreshLibrary();
837-
}, err=>{
838-
showToast(app.name+" removal failed, "+err,"error");
839-
});
843+
.then(startOperation({name:"Remove App"}, () => () => getInstalledApps())
844+
.then(()=> Comms.removeApp(device.appsInstalled.find(a => a.id === app.id))) // a = from appid.info, app = from apps.json
845+
.then(()=>{
846+
device.appsInstalled = device.appsInstalled.filter(a=>a.id!=app.id);
847+
showToast(app.name+" removed successfully","success");
848+
}, err=>{
849+
showToast(app.name+" removal failed, "+err,"error");
850+
}));
840851
}
841852

842853
/** Show window for a new app and finally upload it */
843854
function customApp(app) {
844-
return handleCustomApp(app).then((appJSON) => {
845-
if (appJSON) device.appsInstalled.push(appJSON);
855+
return handleCustomApp(app).then(() => {
846856
showToast(app.name+" Uploaded!", "success");
847857
refreshMyApps();
848858
refreshLibrary();
@@ -913,7 +923,7 @@ if options.noFinish is true, showUploadFinished isn't called (displaying the reb
913923
function updateApp(app, options) {
914924
options = options||{};
915925
if (app.custom) return customApp(app);
916-
return Comms.getAppInfo(app).then(remove => {
926+
return startOperation({name:"Update App"}, () => Comms.getAppInfo(app).then(remove => {
917927
// remove = from appid.info, app = from apps.json
918928
if (remove.files===undefined) remove.files="";
919929
// no need to remove files which will be overwritten anyway
@@ -938,13 +948,7 @@ function updateApp(app, options) {
938948
).then((appJSON) => {
939949
if (appJSON) device.appsInstalled.push(appJSON);
940950
showToast(app.name+" Updated!", "success");
941-
refreshMyApps();
942-
refreshLibrary();
943-
}, err=>{
944-
showToast(app.name+" update failed, "+err,"error");
945-
refreshMyApps();
946-
refreshLibrary();
947-
});
951+
}));
948952
}
949953

950954

@@ -1194,9 +1198,11 @@ function handleConnectionChange(connected) {
11941198
}
11951199

11961200
htmlToArray(document.querySelectorAll(".btn.refresh")).map(button => button.addEventListener("click", () => {
1197-
getInstalledApps(true).catch(err => {
1198-
showToast("Getting app list failed, "+err,"error");
1199-
});
1201+
startOperation({name:"Refresh Apps"}, () =>
1202+
getInstalledApps(true).catch(err => {
1203+
showToast("Getting app list failed, "+err,"error");
1204+
})
1205+
);
12001206
}));
12011207
htmlToArray(document.querySelectorAll(".btn.updateapps")).map(button => button.addEventListener("click", () => {
12021208
updateAllApps();
@@ -1290,33 +1296,31 @@ if (btn) btn.addEventListener("click",event=>{
12901296

12911297
btn = document.getElementById("resetwatch");
12921298
if (btn) btn.addEventListener("click",event=>{
1293-
Comms.resetDevice().then(()=>{
1294-
showToast("Reset watch successfully","success");
1295-
}, err=>{
1296-
showToast("Error resetting watch: "+err,"error");
1297-
});
1299+
startOperation({name:"Reset Watch"}, () =>
1300+
Comms.resetDevice().then(()=>{
1301+
showToast("Reset watch successfully","success");
1302+
}, err=>{
1303+
showToast("Error resetting watch: "+err,"error");
1304+
}));
12981305
});
12991306
btn = document.getElementById("settime");
13001307
if (btn) btn.addEventListener("click",event=>{
1301-
Comms.setTime().then(()=>{
1302-
showToast("Time set successfully","success");
1303-
}, err=>{
1304-
showToast("Error setting time, "+err,"error");
1305-
});
1308+
startOperation({name:"Set Time"}, () =>
1309+
Comms.setTime().then(()=>{
1310+
showToast("Time set successfully","success");
1311+
}, err=>{
1312+
showToast("Error setting time, "+err,"error");
1313+
}));
13061314
});
13071315
btn = document.getElementById("removeall");
13081316
if (btn) btn.addEventListener("click",event=>{
1309-
showPrompt("Remove All","Really remove all apps?").then(() => {
1310-
return Comms.removeAllApps();
1311-
}).then(()=>{
1312-
Progress.hide({sticky:true});
1313-
device.appsInstalled = [];
1314-
showToast("All apps removed","success");
1315-
return getInstalledApps(true);
1316-
}).catch(err=>{
1317-
Progress.hide({sticky:true});
1318-
showToast("App removal failed, "+err,"error");
1319-
});
1317+
showPrompt("Remove All","Really remove all apps?").then(() =>
1318+
startOperation({name:"Remove All Apps"}, () => Comms.removeAllApps()
1319+
.then(()=>{
1320+
device.appsInstalled = [];
1321+
showToast("All apps removed","success");
1322+
return getInstalledApps(true);
1323+
})));
13201324
});
13211325

13221326
// Install all favourite apps in one go
@@ -1328,10 +1332,7 @@ if (btn) btn.addEventListener("click",event => {
13281332
if (!nonCustomFavourites.includes(id))
13291333
nonCustomFavourites.unshift(id);
13301334
});
1331-
installMultipleApps(nonCustomFavourites, "favourite").catch(err=>{
1332-
Progress.hide({sticky:true});
1333-
showToast("App Install failed, "+err,"error");
1334-
});
1335+
startOperation({name:"Install Favourite Apps"}, () => installMultipleApps(nonCustomFavourites, "favourite"));
13351336
});
13361337

13371338
// Create a new issue on github
@@ -1349,52 +1350,52 @@ if (btn) btn.addEventListener("click", event => {
13491350
// Screenshot button
13501351
btn = document.getElementById("screenshot");
13511352
if (btn) btn.addEventListener("click",event=>{
1352-
getInstalledApps(false).then(()=>{
1353-
if (device.id=="BANGLEJS"){
1354-
showPrompt("Screenshot","Screenshots are not supported on Bangle.js 1",{ok:1});
1355-
} else {
1356-
let url;
1357-
Progress.show({title:"Creating screenshot",interval:10,percent:"animate",sticky:true});
1358-
Comms.write("\x10g.dump();\n").then((s)=>{
1359-
let oImage = new Image();
1360-
oImage.onload = function(){
1361-
Progress.show({title:"Converting screenshot",percent:90,sticky:true});
1362-
let oCanvas = document.createElement('canvas');
1363-
oCanvas.width = oImage.width;
1364-
oCanvas.height = oImage.height;
1365-
let oCtx = oCanvas.getContext('2d');
1366-
oCtx.drawImage(oImage, 0, 0);
1367-
url = oCanvas.toDataURL();
1368-
1369-
let screenshotHtml = `
1370-
<div style="text-align: center;">
1371-
<img align="center" src="${url}"></img>
1372-
</div>
1373-
`
1374-
1375-
showPrompt("Save Screenshot?",screenshotHtml, undefined, false).then((r)=>{
1376-
Progress.show({title:"Saving screenshot",percent:99,sticky:true});
1377-
let link = document.createElement("a");
1378-
link.download = "screenshot.png";
1379-
link.target = "_blank";
1380-
link.href = url;
1381-
document.body.appendChild(link);
1382-
link.click();
1383-
document.body.removeChild(link);
1384-
}).catch(()=>{
1385-
}).finally(()=>{
1386-
Progress.hide({sticky:true});
1387-
});
1388-
}
1389-
oImage.src = s.split("\n")[0];
1390-
Progress.hide({sticky:true});
1391-
Progress.show({title:"Screenshot done",percent:85,sticky:true});
1353+
startOperation({name:"Screenshot"}, () =>
1354+
getInstalledApps(false).then(()=>{
1355+
if (device.id=="BANGLEJS"){
1356+
showPrompt("Screenshot","Screenshots are not supported on Bangle.js 1",{ok:1});
1357+
} else {
1358+
let url;
1359+
Progress.show({title:"Creating screenshot",interval:10,percent:"animate",sticky:true});
1360+
return Comms.write("\x10g.dump();\n").then((s)=>{
1361+
let oImage = new Image();
1362+
oImage.onload = function(){
1363+
Progress.show({title:"Converting screenshot",percent:90,sticky:true});
1364+
let oCanvas = document.createElement('canvas');
1365+
oCanvas.width = oImage.width;
1366+
oCanvas.height = oImage.height;
1367+
let oCtx = oCanvas.getContext('2d');
1368+
oCtx.drawImage(oImage, 0, 0);
1369+
url = oCanvas.toDataURL();
1370+
1371+
let screenshotHtml = `
1372+
<div style="text-align: center;">
1373+
<img align="center" src="${url}"></img>
1374+
</div>
1375+
`
1376+
1377+
showPrompt("Save Screenshot?",screenshotHtml, undefined, false).then((r)=>{
1378+
Progress.show({title:"Saving screenshot",percent:99,sticky:true});
1379+
let link = document.createElement("a");
1380+
link.download = "screenshot.png";
1381+
link.target = "_blank";
1382+
link.href = url;
1383+
document.body.appendChild(link);
1384+
link.click();
1385+
document.body.removeChild(link);
1386+
}).catch(() => {
1387+
Progress.hide({sticky:true}); // cancelled
1388+
});
1389+
}
1390+
oImage.src = s.split("\n")[0];
1391+
Progress.hide({sticky:true});
1392+
Progress.show({title:"Screenshot done",percent:85,sticky:true});
13921393

1393-
}, err=>{
1394-
showToast("Error creating screenshot: "+err,"error");
1395-
});
1396-
}
1397-
});
1394+
}, err=>{
1395+
showToast("Error creating screenshot: "+err,"error");
1396+
});
1397+
}
1398+
}));
13981399
});
13991400

14001401
// Open terminal button

0 commit comments

Comments
 (0)