Loading app/index.html +19 −0 Original line number Diff line number Diff line Loading @@ -380,6 +380,25 @@ <div class="card-header" data-translate="download-eos"></div> <div class="card-body"> <p data-translate="this-might-take-some-time-please-be-patient"></p> <div class="download-actions text-center"> <div class="download-buttons"> <button class="next download-build-button"> Download build <span class="btn-loader"></span> </button> <button class="next use-local-zip-button"> Use local ZIP <span class="btn-loader"></span> </button> </div> <input class="local-zip-input" type="file" accept=".zip" hidden /> <p class="local-zip-error" style="display: none; color: red"></p> </div> <div class="text-center large-padding"> <p class="downloading-progress"></p> <progress class="downloading-progress-bar" max="100"></progress> Loading app/src/controller.manager.js +9 −1 Original line number Diff line number Diff line Loading @@ -413,7 +413,7 @@ export class Controller { setResources(resources) { this.resources = resources; if (this.resources.steps) { this.steps.push(new Step("downloading", "download", false)); this.steps.push(new Step("downloading", "download", true)); this.steps.push( ...this.resources.steps.map((step) => { return new Step( Loading @@ -428,4 +428,12 @@ export class Controller { } this.deviceManager.setResources(this.resources.folder, this.steps); } setLocalZip(file) { this.deviceManager.setLocalZipFile(file); } clearLocalZip() { this.deviceManager.clearLocalZipFile(); } } app/src/controller/device.manager.js +29 −7 Original line number Diff line number Diff line Loading @@ -27,6 +27,18 @@ export class DeviceManager { this.wasConnected = false; } setLocalZipFile(file) { this.downloader.setLocalZip(file); } clearLocalZipFile() { this.downloader.clearLocalZip(); } hasLocalZipFile() { return this.downloader.hasLocalZip(); } async init() { await this.bootloader.init(); await this.adb.init(); Loading Loading @@ -187,6 +199,15 @@ export class DeviceManager { async downloadAll(onProgress, onUnzip, onVerify) { try { if (this.downloader.hasLocalZip()) { await this.downloader.ingestLocalZip( this.files, this.folder, onProgress, onUnzip, onVerify, ); } else { await this.downloader.downloadAndUnzipFolder( this.files, this.folder, Loading @@ -194,6 +215,7 @@ export class DeviceManager { onUnzip, onVerify, ); } } catch (e) { throw new Error(`downloadAll error ${e.message || e}`); } Loading app/src/controller/downloader.manager.js +63 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ export class Downloader { constructor() { this.db = null; this.stored = {}; this.localZipFile = null; } async init() { Loading @@ -25,6 +26,18 @@ export class Downloader { this.quota = await navigator.storage.estimate(); } setLocalZip(file) { this.localZipFile = file; } clearLocalZip() { this.localZipFile = null; } hasLocalZip() { return !!this.localZipFile; } /* * */ async downloadAndUnzipFolder( Loading @@ -34,6 +47,8 @@ export class Downloader { onUnzipProgress, onVerifyProgress, ) { await this.clearDBStore(); this.stored = {}; let current_file; try { for (let i = 0; i < folder.length; i++) { Loading Loading @@ -117,6 +132,54 @@ export class Downloader { } } async ingestLocalZip( filesRequired, folder, onDownloadProgress, onUnzipProgress, onVerifyProgress, ) { await this.clearDBStore(); this.stored = {}; if (!this.localZipFile) { throw new Error("No local zip file selected"); } const zipDescriptor = folder.find((f) => f.unzip) || folder[0]; if (!zipDescriptor) { throw new Error("No zip resource found to map local file"); } onDownloadProgress( this.localZipFile.size, this.localZipFile.size, this.localZipFile.name || zipDescriptor.name || "local.zip", ); const zipReader = new ZipReader(new BlobReader(this.localZipFile)); const filesEntries = await zipReader.getEntries(); for (let i = 0; i < filesEntries.length; i++) { const unzippedEntry = await this.getFileFromZip(filesEntries[i], (value, total) => { onUnzipProgress(value, total, filesEntries[i].filename); }); let filename = this.getMappedName( filesEntries[i].filename, zipDescriptor.mapping, ); if (filesRequired.includes(filename)) { await this.setInDBStore(unzippedEntry.blob, filename); this.stored[filename] = true; const fileSHA = await this.computeSha256( unzippedEntry.blob, (loaded, total) => { onVerifyProgress(loaded, total, filename); }, ); console.log(`File: ${unzippedEntry.name} SHA256: ${fileSHA}`); } } await zipReader.close(); } async getFileFromZip(file, onProgress) { const name = file.filename; const blob = await file.getData(new BlobWriter(), { Loading app/src/viewManager.js +64 −8 Original line number Diff line number Diff line Loading @@ -32,6 +32,9 @@ export default class ViewManager { $copyStep.id = step.id; $copyStep.classList.add("active"); $copyStep.classList.remove("inactive"); if (step.name === "downloading") { this.bindDownloadChoice($copyStep, step); } else { const $button = $copyStep.querySelector("button"); if ($button) { $button.addEventListener("click", async (event) => { Loading @@ -39,6 +42,7 @@ export default class ViewManager { await this.executeStep($button, step.name); }); } } let $processCtn = document.getElementById("process-ctn"); if ($processCtn) { $processCtn.appendChild($copyStep); Loading Loading @@ -222,6 +226,57 @@ export default class ViewManager { } // /CONTROLLER EVENTS bindDownloadChoice($copyStep, step) { const downloadBtn = $copyStep.querySelector(".download-build-button"); const localBtn = $copyStep.querySelector(".use-local-zip-button"); const fileInput = $copyStep.querySelector(".local-zip-input"); const errorEl = $copyStep.querySelector(".local-zip-error"); if (downloadBtn) { downloadBtn.addEventListener("click", async (event) => { event.stopPropagation(); if (errorEl) { errorEl.style.display = "none"; errorEl.innerText = ""; } this.controller.clearLocalZip(); await this.executeStep(downloadBtn, step.name); }); } if (localBtn && fileInput) { localBtn.addEventListener("click", (event) => { event.stopPropagation(); if (errorEl) { errorEl.style.display = "none"; errorEl.innerText = ""; } fileInput.value = ""; fileInput.click(); }); fileInput.addEventListener("change", async (evt) => { const file = evt.target.files[0]; if (!file) { return; } if (!file.name.toLowerCase().endsWith(".zip")) { if (errorEl) { errorEl.innerText = "Please select a .zip file."; errorEl.style.display = "block"; } fileInput.value = ""; return; } if (errorEl) { errorEl.style.display = "none"; errorEl.innerText = ""; } this.controller.setLocalZip(file); await this.executeStep(localBtn, step.name); }); } } } document.addEventListener("DOMContentLoaded", async () => { Loading @@ -230,11 +285,12 @@ document.addEventListener("DOMContentLoaded", async () => { let elts = document.querySelectorAll(".card button"); for (let elt of elts) { if (elt.parentElement.parentElement.className.includes("inactive")) { const card = elt.closest(".card"); if (!card || card.className.includes("inactive")) { continue; } elt.addEventListener("click", async () => { VIEW.executeStep(elt, elt.parentElement.parentElement.id); VIEW.executeStep(elt, card.id); }); } }); Loading Loading
app/index.html +19 −0 Original line number Diff line number Diff line Loading @@ -380,6 +380,25 @@ <div class="card-header" data-translate="download-eos"></div> <div class="card-body"> <p data-translate="this-might-take-some-time-please-be-patient"></p> <div class="download-actions text-center"> <div class="download-buttons"> <button class="next download-build-button"> Download build <span class="btn-loader"></span> </button> <button class="next use-local-zip-button"> Use local ZIP <span class="btn-loader"></span> </button> </div> <input class="local-zip-input" type="file" accept=".zip" hidden /> <p class="local-zip-error" style="display: none; color: red"></p> </div> <div class="text-center large-padding"> <p class="downloading-progress"></p> <progress class="downloading-progress-bar" max="100"></progress> Loading
app/src/controller.manager.js +9 −1 Original line number Diff line number Diff line Loading @@ -413,7 +413,7 @@ export class Controller { setResources(resources) { this.resources = resources; if (this.resources.steps) { this.steps.push(new Step("downloading", "download", false)); this.steps.push(new Step("downloading", "download", true)); this.steps.push( ...this.resources.steps.map((step) => { return new Step( Loading @@ -428,4 +428,12 @@ export class Controller { } this.deviceManager.setResources(this.resources.folder, this.steps); } setLocalZip(file) { this.deviceManager.setLocalZipFile(file); } clearLocalZip() { this.deviceManager.clearLocalZipFile(); } }
app/src/controller/device.manager.js +29 −7 Original line number Diff line number Diff line Loading @@ -27,6 +27,18 @@ export class DeviceManager { this.wasConnected = false; } setLocalZipFile(file) { this.downloader.setLocalZip(file); } clearLocalZipFile() { this.downloader.clearLocalZip(); } hasLocalZipFile() { return this.downloader.hasLocalZip(); } async init() { await this.bootloader.init(); await this.adb.init(); Loading Loading @@ -187,6 +199,15 @@ export class DeviceManager { async downloadAll(onProgress, onUnzip, onVerify) { try { if (this.downloader.hasLocalZip()) { await this.downloader.ingestLocalZip( this.files, this.folder, onProgress, onUnzip, onVerify, ); } else { await this.downloader.downloadAndUnzipFolder( this.files, this.folder, Loading @@ -194,6 +215,7 @@ export class DeviceManager { onUnzip, onVerify, ); } } catch (e) { throw new Error(`downloadAll error ${e.message || e}`); } Loading
app/src/controller/downloader.manager.js +63 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ export class Downloader { constructor() { this.db = null; this.stored = {}; this.localZipFile = null; } async init() { Loading @@ -25,6 +26,18 @@ export class Downloader { this.quota = await navigator.storage.estimate(); } setLocalZip(file) { this.localZipFile = file; } clearLocalZip() { this.localZipFile = null; } hasLocalZip() { return !!this.localZipFile; } /* * */ async downloadAndUnzipFolder( Loading @@ -34,6 +47,8 @@ export class Downloader { onUnzipProgress, onVerifyProgress, ) { await this.clearDBStore(); this.stored = {}; let current_file; try { for (let i = 0; i < folder.length; i++) { Loading Loading @@ -117,6 +132,54 @@ export class Downloader { } } async ingestLocalZip( filesRequired, folder, onDownloadProgress, onUnzipProgress, onVerifyProgress, ) { await this.clearDBStore(); this.stored = {}; if (!this.localZipFile) { throw new Error("No local zip file selected"); } const zipDescriptor = folder.find((f) => f.unzip) || folder[0]; if (!zipDescriptor) { throw new Error("No zip resource found to map local file"); } onDownloadProgress( this.localZipFile.size, this.localZipFile.size, this.localZipFile.name || zipDescriptor.name || "local.zip", ); const zipReader = new ZipReader(new BlobReader(this.localZipFile)); const filesEntries = await zipReader.getEntries(); for (let i = 0; i < filesEntries.length; i++) { const unzippedEntry = await this.getFileFromZip(filesEntries[i], (value, total) => { onUnzipProgress(value, total, filesEntries[i].filename); }); let filename = this.getMappedName( filesEntries[i].filename, zipDescriptor.mapping, ); if (filesRequired.includes(filename)) { await this.setInDBStore(unzippedEntry.blob, filename); this.stored[filename] = true; const fileSHA = await this.computeSha256( unzippedEntry.blob, (loaded, total) => { onVerifyProgress(loaded, total, filename); }, ); console.log(`File: ${unzippedEntry.name} SHA256: ${fileSHA}`); } } await zipReader.close(); } async getFileFromZip(file, onProgress) { const name = file.filename; const blob = await file.getData(new BlobWriter(), { Loading
app/src/viewManager.js +64 −8 Original line number Diff line number Diff line Loading @@ -32,6 +32,9 @@ export default class ViewManager { $copyStep.id = step.id; $copyStep.classList.add("active"); $copyStep.classList.remove("inactive"); if (step.name === "downloading") { this.bindDownloadChoice($copyStep, step); } else { const $button = $copyStep.querySelector("button"); if ($button) { $button.addEventListener("click", async (event) => { Loading @@ -39,6 +42,7 @@ export default class ViewManager { await this.executeStep($button, step.name); }); } } let $processCtn = document.getElementById("process-ctn"); if ($processCtn) { $processCtn.appendChild($copyStep); Loading Loading @@ -222,6 +226,57 @@ export default class ViewManager { } // /CONTROLLER EVENTS bindDownloadChoice($copyStep, step) { const downloadBtn = $copyStep.querySelector(".download-build-button"); const localBtn = $copyStep.querySelector(".use-local-zip-button"); const fileInput = $copyStep.querySelector(".local-zip-input"); const errorEl = $copyStep.querySelector(".local-zip-error"); if (downloadBtn) { downloadBtn.addEventListener("click", async (event) => { event.stopPropagation(); if (errorEl) { errorEl.style.display = "none"; errorEl.innerText = ""; } this.controller.clearLocalZip(); await this.executeStep(downloadBtn, step.name); }); } if (localBtn && fileInput) { localBtn.addEventListener("click", (event) => { event.stopPropagation(); if (errorEl) { errorEl.style.display = "none"; errorEl.innerText = ""; } fileInput.value = ""; fileInput.click(); }); fileInput.addEventListener("change", async (evt) => { const file = evt.target.files[0]; if (!file) { return; } if (!file.name.toLowerCase().endsWith(".zip")) { if (errorEl) { errorEl.innerText = "Please select a .zip file."; errorEl.style.display = "block"; } fileInput.value = ""; return; } if (errorEl) { errorEl.style.display = "none"; errorEl.innerText = ""; } this.controller.setLocalZip(file); await this.executeStep(localBtn, step.name); }); } } } document.addEventListener("DOMContentLoaded", async () => { Loading @@ -230,11 +285,12 @@ document.addEventListener("DOMContentLoaded", async () => { let elts = document.querySelectorAll(".card button"); for (let elt of elts) { if (elt.parentElement.parentElement.className.includes("inactive")) { const card = elt.closest(".card"); if (!card || card.className.includes("inactive")) { continue; } elt.addEventListener("click", async () => { VIEW.executeStep(elt, elt.parentElement.parentElement.id); VIEW.executeStep(elt, card.id); }); } }); Loading