|
9 | 9 | <!-- Toggle Buttons --> |
10 | 10 | <div class="btn-group" style="margin: 1em; display: flex; justify-content: center;"> |
11 | 11 | <button id="tableButton" class="btn btn-primary">View Table</button> |
12 | | - <button id="pieChartButton" class="btn">View Pie Charts</button> |
| 12 | + <button id="pieChartButton" class="btn">View Pie Chart</button> |
13 | 13 | </div> |
14 | 14 |
|
15 | 15 | <!-- Table View --> |
16 | 16 | <div id="storageTable"></div> |
17 | 17 |
|
18 | | - <!-- Charts View --> |
19 | | - <div id="storagePieCharts" style="display: none; flex-direction: column; align-items: center; gap: 1.5em;"> |
20 | | - <!-- App Breakdown Chart --> |
| 18 | + <!-- Chart View --> |
| 19 | + <div id="storagePieChart" style="display: none; flex-direction: column; align-items: center;"> |
21 | 20 | <div id="piechart" style="width: 100%; max-width: 600px; height: 400px;"></div> |
22 | | - <!-- Total Storage Chart --> |
23 | 21 | <div id="totalStoragePie" style="width: 100%; max-width: 600px; height: 300px;"></div> |
24 | 22 | </div> |
25 | 23 |
|
26 | 24 | <script> |
27 | 25 | let globalApps = []; |
28 | 26 | let storageStats = null; |
29 | | - let hasGetStats = true; |
30 | | - |
| 27 | + |
31 | 28 | function onInit(device) { |
32 | 29 | Util.showModal("Reading Storage..."); |
33 | | - |
34 | | - // Fetch app list and stats from the watch |
35 | 30 | Puck.eval(`(()=>{ |
36 | | - const Storage = require("Storage"); |
37 | | - const getApps = () => Storage.list(/\\.info$/).map(n => { |
38 | | - const app = Storage.readJSON(n,1)||{}; |
39 | | - let fileSize=0, dataSize=0; |
40 | | - if (app.files) app.files.split(",").forEach(f=>{ |
41 | | - const d = Storage.read(f); if (d) fileSize += d.length; |
42 | | - }); |
43 | | - const parts = (app.data||"").split(";"); |
44 | | - function toRegExp(wc) { return new RegExp("^"+wc.replace(/[.+?^${}()|[\\]\\\\]/g,"\\\\$&").replace(/\\*/g,".*")+"$"); } |
45 | | - if (parts[0]) parts[0].split(",").forEach(wc=>{ |
46 | | - Storage.list(toRegExp(wc), {sf:false}).forEach(f=>{const d=Storage.read(f); if (d) dataSize += d.length;}); |
| 31 | + let getApps = () => require("Storage").list(/\\.info$/).map(appInfoName => { |
| 32 | + let appInfo = require("Storage").readJSON(appInfoName,1)||{}; |
| 33 | + var fileSize = 0, dataSize = 0; |
| 34 | + appInfo.files.split(",").forEach(f => fileSize += require("Storage").read(f).length); |
| 35 | + var data = (appInfo.data||"").split(";"); |
| 36 | + function wildcardToRegexp(wc) { |
| 37 | + return new RegExp("^"+wc.replaceAll(".","\\\\.").replaceAll("?",".*")+"$"); |
| 38 | + } |
| 39 | + if (data[0]) data[0].split(",").forEach(wc => { |
| 40 | + require("Storage").list(wildcardToRegexp(wc), {sf:false}).forEach(f => { |
| 41 | + dataSize += require("Storage").read(f).length |
| 42 | + }); |
47 | 43 | }); |
48 | | - if (parts[1]) parts[1].split(",").forEach(wc=>{ |
49 | | - Storage.list(toRegExp(wc), {sf:true}).forEach(f=>{ try{ dataSize += Storage.open(f,"r").getLength(); }catch(e){} }); |
| 44 | + if (data[1]) data[1].split(",").forEach(wc => { |
| 45 | + require("Storage").list(wildcardToRegexp(wc), {sf:true}).forEach(f => { |
| 46 | + dataSize += require("Storage").open(f,"r").getLength(); |
| 47 | + }); |
50 | 48 | }); |
51 | | - return [app.id||"Unknown", fileSize, dataSize]; |
| 49 | + return [appInfo.id, fileSize, dataSize]; |
52 | 50 | }); |
53 | | -
|
54 | | - let stats; |
55 | | - try { stats = Storage.getStats(); } catch(e) { stats = null; } |
56 | | - return [getApps(), stats]; |
57 | | - })()`, function(result) { |
| 51 | + return [getApps(), require(\"Storage\").getStats()]; })()`, function(result) { |
58 | 52 | Util.hideModal(); |
59 | | - globalApps = result[0].sort((a,b)=>(b[1]+b[2])-(a[1]+a[2])); |
| 53 | + globalApps = result[0].sort((a,b) => (b[1]+b[2]) - (a[1]+a[2])); |
60 | 54 | storageStats = result[1]; |
61 | | - hasGetStats = !!storageStats; |
62 | 55 |
|
63 | 56 | if (globalApps.length === 0) { |
64 | 57 | document.getElementById("storageTable").innerHTML = "<p>No apps found</p>"; |
|
75 | 68 | <thead> |
76 | 69 | <tr> |
77 | 70 | <th>App</th> |
78 | | - <th>Code (KB)</th> |
79 | | - <th>Data (KB)</th> |
80 | | - <th>Total (KB)</th> |
| 71 | + <th>Code (kb)</th> |
| 72 | + <th>Data (kb)</th> |
| 73 | + <th>Total (kb)</th> |
81 | 74 | </tr> |
82 | 75 | </thead> |
83 | 76 | <tbody> |
|
92 | 85 | </table>`; |
93 | 86 | } |
94 | 87 |
|
95 | | - function drawCharts() { |
| 88 | + function drawChart() { |
96 | 89 | if (globalApps.length === 0) return; |
97 | 90 |
|
98 | | - // Chart 1: App Breakdown |
99 | | - const appData = google.visualization.arrayToDataTable([ |
100 | | - ['App', 'Total Size (KB)'], |
101 | | - ...globalApps.map(a => [a[0], (a[1]+a[2])/1000]) |
102 | | - ]); |
| 91 | + // App-specific chart |
| 92 | + const chartData = [ |
| 93 | + ['App', 'Total Size (KB)'] |
| 94 | + ].concat(globalApps.map(app => [app[0], (app[1] + app[2])/1000])); |
| 95 | + |
| 96 | + const data = google.visualization.arrayToDataTable(chartData); |
103 | 97 |
|
104 | | - const appChart = new google.visualization.PieChart(document.getElementById('piechart')); |
105 | | - appChart.draw(appData, { |
| 98 | + const options = { |
106 | 99 | title: 'App Storage Breakdown', |
107 | 100 | chartArea: { width: '90%', height: '80%' }, |
108 | 101 | legend: { position: 'bottom' } |
109 | | - }); |
110 | | - |
111 | | - // Chart 2: Total Storage (only if stats available, i.e., Bangle.js 2) |
112 | | - const totalDiv = document.getElementById('totalStoragePie'); |
113 | | - if (!hasGetStats) { |
114 | | - totalDiv.style.display = "none"; // hide for Bangle.js 1 |
115 | | - return; |
| 102 | + }; |
| 103 | + |
| 104 | + const chart = new google.visualization.PieChart(document.getElementById('piechart')); |
| 105 | + chart.draw(data, options); |
| 106 | + |
| 107 | + // Total storage chart |
| 108 | + if (storageStats) { |
| 109 | + const usedKB = storageStats.fileBytes / 1000; |
| 110 | + const freeKB = storageStats.freeBytes / 1000; |
| 111 | + const trashKB = storageStats.trashBytes / 1000; |
| 112 | + const totalData = google.visualization.arrayToDataTable([ |
| 113 | + ['Type', 'KB'], |
| 114 | + ['Used', usedKB], |
| 115 | + ['Free', freeKB], |
| 116 | + ['Trash', trashKB], |
| 117 | + ]); |
| 118 | + |
| 119 | + const totalOptions = { |
| 120 | + title: 'Total Storage Usage', |
| 121 | + |
| 122 | + chartArea: { width: '90%', height: '80%' }, |
| 123 | + legend: { position: 'bottom' } |
| 124 | + }; |
| 125 | + |
| 126 | + const totalChart = new google.visualization.PieChart(document.getElementById('totalStoragePie')); |
| 127 | + totalChart.draw(totalData, totalOptions); |
116 | 128 | } |
117 | | - |
118 | | - const used = (storageStats.fileBytes||0)/1000; |
119 | | - const free = (storageStats.freeBytes||0)/1000; |
120 | | - const trash = (storageStats.garbageBytes||0)/1000; |
121 | | - |
122 | | - const totalData = google.visualization.arrayToDataTable([ |
123 | | - ['Type', 'KB'], |
124 | | - ['Used', used], |
125 | | - ['Free', free], |
126 | | - ['Trash', trash] |
127 | | - ]); |
128 | | - |
129 | | - const totalChart = new google.visualization.PieChart(totalDiv); |
130 | | - totalChart.draw(totalData, { |
131 | | - title: 'Total Storage Usage', |
132 | | - pieHole: 0.4, |
133 | | - chartArea: { width: '90%', height: '80%' }, |
134 | | - legend: { position: 'bottom' } |
135 | | - }); |
136 | 129 | } |
137 | 130 |
|
138 | | - // Load Google Charts |
139 | 131 | google.charts.load('current', {'packages':['corechart']}); |
| 132 | + |
140 | 133 |
|
141 | | - document.getElementById("pieChartButton").addEventListener("click", function() { |
| 134 | + document.getElementById("pieChartButton").addEventListener("click", function () { |
142 | 135 | document.getElementById("storageTable").style.display = "none"; |
143 | | - document.getElementById("storagePieCharts").style.display = "flex"; |
144 | | - google.charts.setOnLoadCallback(drawCharts); |
| 136 | + document.getElementById("storagePieChart").style.display = "flex"; |
| 137 | + drawChart(); |
145 | 138 | this.classList.add("btn-primary"); |
146 | 139 | document.getElementById("tableButton").classList.remove("btn-primary"); |
147 | 140 | }); |
148 | 141 |
|
149 | | - document.getElementById("tableButton").addEventListener("click", function() { |
| 142 | + document.getElementById("tableButton").addEventListener("click", function () { |
150 | 143 | document.getElementById("storageTable").style.display = "block"; |
151 | | - document.getElementById("storagePieCharts").style.display = "none"; |
| 144 | + document.getElementById("storagePieChart").style.display = "none"; |
152 | 145 | drawTable(); |
153 | 146 | this.classList.add("btn-primary"); |
154 | 147 | document.getElementById("pieChartButton").classList.remove("btn-primary"); |
155 | 148 | }); |
156 | | - |
157 | | - window.onInit = onInit; |
| 149 | + |
158 | 150 | </script> |
159 | 151 | </body> |
160 | 152 | </html> |
0 commit comments