Skip to content

Commit 912026a

Browse files
committed
Add device storage info
1 parent 1cdcb34 commit 912026a

File tree

2 files changed

+44
-14
lines changed

2 files changed

+44
-14
lines changed

js/comms.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,9 @@ const Comms = {
196196
});
197197
});
198198
},
199-
// Get Device ID and version, plus a JSON list of installed apps
199+
// Get Device ID, version, storage stats, and a JSON list of installed apps
200200
getDeviceInfo : (noReset) => {
201-
Progress.show({title:`Getting app list...`,sticky:true});
201+
Progress.show({title:`Getting device info...`,sticky:true});
202202
return new Promise((resolve,reject) => {
203203
Puck.write("\x03",(result) => {
204204
if (result===null) {
@@ -240,7 +240,7 @@ const Comms = {
240240
return;
241241
}
242242

243-
let cmd, finalJS = `E.toJS([process.env.BOARD,process.env.VERSION,process.env.EXPTR,0|getTime(),E.CRC32(getSerial()+NRF.getAddress())]).substr(1)`;
243+
let cmd, finalJS = `JSON.stringify(require("Storage").getStats?require("Storage").getStats():{})+","+E.toJS([process.env.BOARD,process.env.VERSION,process.env.EXPTR,0|getTime(),E.CRC32(getSerial()+NRF.getAddress())]).substr(1)`;
244244
if (Const.SINGLE_APP_ONLY) // only one app on device, info file is in app.info
245245
cmd = `\x10Bluetooth.println("["+(require("Storage").read("app.info")||"null")+","+${finalJS})\n`;
246246
else
@@ -259,12 +259,13 @@ const Comms = {
259259
let appList;
260260
try {
261261
appList = JSON.parse(appListJSON);
262-
// unpack the last 4 elements which are board info (See finalJS above)
262+
// unpack the last 6 elements which are board info (See finalJS above)
263263
info.uid = appList.pop(); // unique ID for watch (hash of internal serial number and MAC)
264264
info.currentTime = appList.pop()*1000; // time in ms
265265
info.exptr = appList.pop(); // used for compilation
266266
info.version = appList.pop();
267267
info.id = appList.pop();
268+
info.storageStats = appList.pop(); // how much storage has been used
268269
// if we just have 'null' then it means we have no apps
269270
if (appList.length==1 && appList[0]==null)
270271
appList = [];

js/index.js

+39-10
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ function handleCustomApp(appTemplate) {
320320
if (!appTemplate.custom) throw new Error("App doesn't have custom HTML");
321321
// if it needs a connection, do that first
322322
if (appTemplate.customConnect && !device.connected)
323-
return getInstalledApps().then(() => handleCustomApp(appTemplate));
323+
return getDeviceInfo().then(() => handleCustomApp(appTemplate));
324324
// otherwise continue
325325
return new Promise((resolve,reject) => {
326326
let modal = htmlElement(`<div class="modal active">
@@ -358,7 +358,7 @@ function handleCustomApp(appTemplate) {
358358
console.log("Received custom app", app);
359359
modal.remove();
360360

361-
getInstalledApps()
361+
getDeviceInfo()
362362
.then(()=>checkDependencies(app))
363363
.then(()=>Comms.uploadApp(app,{device:device, language:LANGUAGE, noFinish: msg.options && msg.options.noFinish}))
364364
.then(()=>{
@@ -745,7 +745,7 @@ function showScreenshots(appId) {
745745
// =========================================== My Apps
746746

747747
function uploadApp(app) {
748-
return getInstalledApps().then(()=>{
748+
return getDeviceInfo().then(()=>{
749749
if (device.appsInstalled.some(i => i.id === app.id)) {
750750
return updateApp(app);
751751
}
@@ -774,7 +774,7 @@ function uploadApp(app) {
774774

775775
function removeApp(app) {
776776
return showPrompt("Delete","Really remove '"+app.name+"'?").then(() => {
777-
return getInstalledApps().then(()=>{
777+
return getDeviceInfo().then(()=>{
778778
// a = from appid.info, app = from apps.json
779779
return Comms.removeApp(device.appsInstalled.find(a => a.id === app.id));
780780
});
@@ -983,7 +983,7 @@ function refreshMyApps() {
983983
}
984984

985985
let haveInstalledApps = false;
986-
function getInstalledApps(refresh) {
986+
function getDeviceInfo(refresh) {
987987
if (haveInstalledApps && !refresh) {
988988
return Promise.resolve(device.appsInstalled);
989989
}
@@ -995,6 +995,7 @@ function getInstalledApps(refresh) {
995995
device.id = info.id;
996996
device.version = info.version;
997997
device.exptr = info.exptr;
998+
device.storageStats = info.storageStats;
998999
device.appsInstalled = info.apps;
9991000
haveInstalledApps = true;
10001001
if ("function"==typeof onFoundDeviceInfo)
@@ -1016,11 +1017,39 @@ function getInstalledApps(refresh) {
10161017
const deviceInfoElem = document.getElementById("more-deviceinfo");
10171018
if (deviceInfoElem) {
10181019
deviceInfoElem.style.display = "inherit";
1020+
let storageRow = "";
1021+
if (device.storageStats?.totalBytes) {
1022+
const stats = device.storageStats;
1023+
const totalKB = (stats.totalBytes / 1000).toFixed(2);
1024+
const usedKB = (stats.fileBytes / 1000).toFixed(2);
1025+
const trashKB = (stats.trashBytes / 1000).toFixed(2);
1026+
const freeKB = (stats.freeBytes / 1000).toFixed(2);
1027+
const bytePrc = 100 / stats.totalBytes;
1028+
const usedPrc = bytePrc * stats.fileBytes;
1029+
const trashPrc = bytePrc * stats.trashBytes;
1030+
const freePrc = bytePrc * stats.freeBytes;
1031+
if (isNaN(usedPrc) || isNaN(trashPrc) || isNaN(freePrc)) {
1032+
console.error("Unexpected error: Could not calculate storage statistics");
1033+
} else {
1034+
storageRow = `
1035+
<tr><td><b>Storage</b></td><td>
1036+
<p style="margin-bottom:.4rem;">${totalKB} KiB in total, ${stats.fileCount} files used, ${stats.trashCount} files trashed.</p>
1037+
<div class="bar" style="margin-bottom:.3rem;">
1038+
<!-- These styles prevent overflow of text if the bar item is too small to fit all the text -->
1039+
<style>.bar-item{white-space:nowrap;padding-left:.1rem;padding-right:.1rem;}</style>
1040+
<div class="bar-item tooltip bg-error" data-tooltip="${usedKB} KiB, ${usedPrc.toFixed(2)}% used" style="width:${usedPrc}%; color:hsl(218 16% 2%)">${usedPrc.toFixed(0)}% used</div>
1041+
<div class="bar-item tooltip bg-warning" data-tooltip="${trashKB} KiB, ${trashPrc.toFixed(2)}% trash" style="width:${trashPrc}%;color:hsl(218 16% 7%)">${trashPrc.toFixed(0)}% trash</div>
1042+
<div class="bar-item tooltip bg-success" data-tooltip="${freeKB} KiB, ${freePrc.toFixed(2)}% free" style="width:${freePrc}%; color:hsl(218 16% 7%)">${freePrc.toFixed(0)}% free</div>
1043+
</div>
1044+
</td></tr>`;
1045+
}
1046+
}
10191047
const deviceInfoContentElem = document.getElementById("more-deviceinfo-content");
10201048
deviceInfoContentElem.innerHTML = `
10211049
<table class="table"><tbody>
10221050
<tr><td><b>Device Type</b></td><td>${device.id}</td></tr>
10231051
<tr><td><b>Firmware Version</b></td><td>${device.version}</td></tr>
1052+
${storageRow}
10241053
<tr><td><b>Apps Installed</b></td><td>${(device.appsInstalled || []).map(a => `${a.id} (${a.version})`).join(", ")}</td></tr>
10251054
</tbody></table>`;
10261055
}
@@ -1064,7 +1093,7 @@ function installMultipleApps(appIds, promptName) {
10641093
).then(()=> Comms.showUploadFinished()
10651094
).then(()=>{
10661095
showToast("Apps successfully installed!","success");
1067-
return getInstalledApps(true);
1096+
return getDeviceInfo(true);
10681097
});
10691098
}
10701099

@@ -1110,7 +1139,7 @@ function handleConnectionChange(connected) {
11101139
}
11111140

11121141
htmlToArray(document.querySelectorAll(".btn.refresh")).map(button => button.addEventListener("click", () => {
1113-
getInstalledApps(true).catch(err => {
1142+
getDeviceInfo(true).catch(err => {
11141143
showToast("Getting app list failed, "+err,"error");
11151144
});
11161145
}));
@@ -1123,7 +1152,7 @@ connectMyDeviceBtn.addEventListener("click", () => {
11231152
const deviceInfoElem = document.getElementById("more-deviceinfo");
11241153
if (deviceInfoElem) deviceInfoElem.style.display = "none";
11251154
} else {
1126-
getInstalledApps(true).catch(err => {
1155+
getDeviceInfo(true).catch(err => {
11271156
showToast("Device connection failed, "+err,"error");
11281157
Comms.disconnectDevice();
11291158
});
@@ -1243,7 +1272,7 @@ if (btn) btn.addEventListener("click",event=>{
12431272
Progress.hide({sticky:true});
12441273
device.appsInstalled = [];
12451274
showToast("All apps removed","success");
1246-
return getInstalledApps(true);
1275+
return getDeviceInfo(true);
12471276
}).catch(err=>{
12481277
Progress.hide({sticky:true});
12491278
showToast("App removal failed, "+err,"error");
@@ -1279,7 +1308,7 @@ if (btn) btn.addEventListener("click", event => {
12791308

12801309
btn = document.getElementById("screenshot");
12811310
if (btn) btn.addEventListener("click",event=>{
1282-
getInstalledApps(false).then(()=>{
1311+
getDeviceInfo(false).then(()=>{
12831312
if (device.id=="BANGLEJS"){
12841313
showPrompt("Screenshot","Screenshots are not supported on Bangle.js 1",{ok:1});
12851314
} else {

0 commit comments

Comments
 (0)