+
+
+
+
+
+
+
diff --git a/app/src/controller.manager.js b/app/src/controller.manager.js
index bfe32a731f9603d3f4be2d111ef9e11af8ab6ec9..337ad1272b1bcb48e515b088403bff73f3db35ce 100644
--- a/app/src/controller.manager.js
+++ b/app/src/controller.manager.js
@@ -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(
@@ -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();
+ }
}
diff --git a/app/src/controller/device.manager.js b/app/src/controller/device.manager.js
index 74aff737139366989a321faacb6fa9f4f8c7ecf9..f86ace72dd77d76d995b56c250e8eba3367fdb00 100644
--- a/app/src/controller/device.manager.js
+++ b/app/src/controller/device.manager.js
@@ -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();
@@ -187,13 +199,23 @@ export class DeviceManager {
async downloadAll(onProgress, onUnzip, onVerify) {
try {
- await this.downloader.downloadAndUnzipFolder(
- this.files,
- this.folder,
- onProgress,
- onUnzip,
- onVerify,
- );
+ if (this.downloader.hasLocalZip()) {
+ await this.downloader.ingestLocalZip(
+ this.files,
+ this.folder,
+ onProgress,
+ onUnzip,
+ onVerify,
+ );
+ } else {
+ await this.downloader.downloadAndUnzipFolder(
+ this.files,
+ this.folder,
+ onProgress,
+ onUnzip,
+ onVerify,
+ );
+ }
} catch (e) {
throw new Error(`downloadAll error ${e.message || e}`);
}
diff --git a/app/src/controller/downloader.manager.js b/app/src/controller/downloader.manager.js
index 4a2937cf281aab51fa2c56d634b09db9ee48af7e..ee732eb014bcb5def1a0c1f00b94cee89b4a4f2f 100644
--- a/app/src/controller/downloader.manager.js
+++ b/app/src/controller/downloader.manager.js
@@ -15,6 +15,7 @@ export class Downloader {
constructor() {
this.db = null;
this.stored = {};
+ this.localZipFile = null;
}
async init() {
@@ -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(
@@ -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++) {
@@ -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(), {
diff --git a/app/src/viewManager.js b/app/src/viewManager.js
index d122881e6c0b1f41614e44467b731af1ba30d643..3133a25d3e8c48b3ec39de051942b3674d3795f5 100644
--- a/app/src/viewManager.js
+++ b/app/src/viewManager.js
@@ -32,12 +32,16 @@ export default class ViewManager {
$copyStep.id = step.id;
$copyStep.classList.add("active");
$copyStep.classList.remove("inactive");
- const $button = $copyStep.querySelector("button");
- if ($button) {
- $button.addEventListener("click", async (event) => {
- event.stopPropagation();
- await this.executeStep($button, step.name);
- });
+ if (step.name === "downloading") {
+ this.bindDownloadChoice($copyStep, step);
+ } else {
+ const $button = $copyStep.querySelector("button");
+ if ($button) {
+ $button.addEventListener("click", async (event) => {
+ event.stopPropagation();
+ await this.executeStep($button, step.name);
+ });
+ }
}
let $processCtn = document.getElementById("process-ctn");
if ($processCtn) {
@@ -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 () => {
@@ -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);
});
}
});