diff --git a/build.js b/build.js index 7e309692..4a12d20a 100755 --- a/build.js +++ b/build.js @@ -1,6 +1,6 @@ #!/usr/bin/env node -"use strict" +"use strict"; /* @@ -10,63 +10,92 @@ Author: Marius Gripsgard */ -const builder = require("electron-builder") +const builder = require("electron-builder"); const cli = require("commander"); const unzip = require("unzipper"); const path = require("path"); const fs = require("fs-extra"); -const download = require('download'); +const download = require("download"); const events = require("events"); class event extends events {} -const Platform = builder.Platform -const platformToolsPath = "./platform-tools" +const Platform = builder.Platform; +const platformToolsPath = "./platform-tools"; const platformToolsUrls = { - "linux": "https://dl.google.com/android/repository/platform-tools-latest-linux.zip", - "mac": "https://dl.google.com/android/repository/platform-tools-latest-darwin.zip", - "win": "https://dl.google.com/android/repository/platform-tools-latest-windows.zip" -} + linux: + "https://dl.google.com/android/repository/platform-tools-latest-linux.zip", + mac: + "https://dl.google.com/android/repository/platform-tools-latest-darwin.zip", + win: + "https://dl.google.com/android/repository/platform-tools-latest-windows.zip" +}; function getAndroidPlatformTools() { - return [{ - url: platformToolsUrls[cli.os], - path: platformToolsPath, - target: cli.os - }]; + return [ + { + url: platformToolsUrls[cli.os], + path: platformToolsPath, + target: cli.os + } + ]; } function extractPlatformTools(platformToolsArray, callback) { var i = platformToolsArray[0]; - fs.createReadStream(path.join(i.path, path.basename(i.url))).pipe(unzip.Extract({ - path: path.join(i.path, i.target + "_tmp") - })).on("close", () => { - fs.move(path.join(i.path, i.target + "_tmp", "platform-tools"), path.join(i.path, i.target), { - overwrite: true - }, (e) => { - fs.removeSync(path.join(i.path, i.target + "_tmp")); - if (cli.os !== "win") { - fs.chmodSync(path.join(i.path, i.target, "fastboot"), 0o755); - fs.chmodSync(path.join(i.path, i.target, "adb"), 0o755); - fs.chmodSync(path.join(i.path, i.target, "mke2fs"), 0o755); - } - if (platformToolsArray.length <= 1) { - callback() - } else { - platformToolsArray.shift(); - extractPlatformTools(platformToolsArray, callback); - } + fs.createReadStream(path.join(i.path, path.basename(i.url))) + .pipe( + unzip.Extract({ + path: path.join(i.path, i.target + "_tmp") + }) + ) + .on("close", () => { + fs.move( + path.join(i.path, i.target + "_tmp", "platform-tools"), + path.join(i.path, i.target), + { + overwrite: true + }, + e => { + fs.removeSync(path.join(i.path, i.target + "_tmp")); + if (cli.os !== "win") { + fs.chmodSync(path.join(i.path, i.target, "fastboot"), 0o755); + fs.chmodSync(path.join(i.path, i.target, "adb"), 0o755); + fs.chmodSync(path.join(i.path, i.target, "mke2fs"), 0o755); + } + if (platformToolsArray.length <= 1) { + callback(); + } else { + platformToolsArray.shift(); + extractPlatformTools(platformToolsArray, callback); + } + } + ); }); - }); } cli - .version(require('./package.json').version) - .usage('./build.js -o -p [options]') - .option('-o, --os ', 'Target operating system') - .option('-p, --package [package]', 'Target package') - .option('-e, --extra-metadata [JSON]', 'Inject JSON into package.json', JSON.parse, "") - .option('-d, --download-only', 'Only download platform tools', undefined, false) - .option('-n, --no-platform-tools', 'Build without platform tools', undefined, false) - .parse(process.argv) + .version(require("./package.json").version) + .usage("./build.js -o -p [options]") + .option("-o, --os ", "Target operating system") + .option("-p, --package [package]", "Target package") + .option( + "-e, --extra-metadata [JSON]", + "Inject JSON into package.json", + JSON.parse, + "" + ) + .option( + "-d, --download-only", + "Only download platform tools", + undefined, + false + ) + .option( + "-n, --no-platform-tools", + "Build without platform tools", + undefined, + false + ) + .parse(process.argv); var targetOs; var buildConfig = require("./buildconfig-generic.json"); @@ -80,38 +109,44 @@ switch (cli.os) { case "linux": targetOs = Platform.LINUX; buildConfig = Object.assign(buildConfig, { - "linux": { - "target": cli.package, - "icon": "build/icons", - "synopsis": "Install Ubuntu Touch on UBports devices", - "category": "Utility" - }, - "deb": { - "depends": ["gconf2", "gconf-service", "libnotify4", "libappindicator1", "libxtst6", "libnss3", "android-tools-adb", "android-tools-fastboot"] - } + linux: { + target: cli.package, + icon: "build/icons", + synopsis: "Install Ubuntu Touch on UBports devices", + category: "Utility" + }, + deb: { + depends: [ + "gconf2", + "gconf-service", + "libnotify4", + "libappindicator1", + "libxtst6", + "libnss3", + "android-tools-adb", + "android-tools-fastboot" + ] } - ); + }); break; case "win": targetOs = Platform.WINDOWS; buildConfig = Object.assign(buildConfig, { - "win": { - "target": ["portable"], - "icon": "build/icons/icon.ico" - } + win: { + target: ["portable"], + icon: "build/icons/icon.ico" } - ); + }); break; case "mac": targetOs = Platform.MAC; buildConfig = Object.assign(buildConfig, { - "mac": { - "target": "dmg", - "icon": "build/icons/icon.icns", - "category": "public.app-category.utilities" - } + mac: { + target: "dmg", + icon: "build/icons/icon.icns", + category: "public.app-category.utilities" } - ); + }); break; default: console.log("Please specify a target operating system!"); @@ -154,42 +189,46 @@ switch (cli.package) { var build = () => { // Build if (!cli.downloadOnly) { - builder.build({ + builder + .build({ targets: builder.createTargets([targetOs]), - config: Object.assign(buildConfig, - { "extraMetadata": - (cli.package ? - Object.assign(cli.extraMetadata, { "package": cli.package }) : - cli.extraMetadata - ) - } - ) - }).then(() => { - console.log("Done"); - }).catch((e) => { - if(e.message.indexOf("GitHub Personal Access Token is not set") !== -1) { + config: Object.assign(buildConfig, { + extraMetadata: cli.package + ? Object.assign(cli.extraMetadata, { package: cli.package }) + : cli.extraMetadata + }) + }) + .then(() => { console.log("Done"); - process.exit(0); - } else { - console.log(e); - process.exit(1); - } - }); + }) + .catch(e => { + if ( + e.message.indexOf("GitHub Personal Access Token is not set") !== -1 + ) { + console.log("Done"); + process.exit(0); + } else { + console.log(e); + process.exit(1); + } + }); } -} +}; // Download platform tools if (cli.platformTools) { - download(getAndroidPlatformTools()[0].url,getAndroidPlatformTools()[0].path).then(() => { - console.log('files downloaded!'); - extractPlatformTools(getAndroidPlatformTools(), () => { - console.log("Platform tools downloaded successfully!"); - if (!cli.downloadOnly) build(); + download(getAndroidPlatformTools()[0].url, getAndroidPlatformTools()[0].path) + .then(() => { + console.log("files downloaded!"); + extractPlatformTools(getAndroidPlatformTools(), () => { + console.log("Platform tools downloaded successfully!"); + if (!cli.downloadOnly) build(); + }); + }) + .catch(() => { + console.error("Failed to download files!"); + process.exit(1); }); - }).catch(() => { - console.error("Failed to download files!"); - process.exit(1); - }); } else { build(); } diff --git a/package-lock.json b/package-lock.json index 7c7d17ed..657182c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "ubports-installer", - "version": "0.4.6-beta", + "version": "0.4.7-beta", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index ff63e62c..43fd962e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ubports-installer", - "version": "0.4.6-beta", + "version": "0.4.7-beta", "description": "The easy way to install Ubuntu Touch on UBports devices. A friendly cross-platform Installer for Ubuntu Touch. Just connect a supported device to your PC, follow the on-screen instructions and watch this awesome tool do all the rest.", "keywords": [ "Ubuntu", @@ -30,8 +30,8 @@ "dist:linux:appimage": "node ./build.js -o 'linux' -p 'AppImage'", "dist:linux:deb": "node ./build.js -o 'linux' -p 'deb'", "dist:linux:snap": "snapcraft cleanbuild", - "lint": "./node_modules/.bin/eslint src/*.js", - "lint-fix": "./node_modules/.bin/eslint src/*.js --fix" + "lint": "./node_modules/.bin/eslint *.js src/*.js src/html/scripts/*.js", + "lint-fix": "./node_modules/.bin/eslint *.js src/*.js src/html/scripts/*.js --fix" }, "devDependencies": { "electron": "^1.8.8", diff --git a/src/devices.js b/src/devices.js index 44dca74d..a0a5062f 100644 --- a/src/devices.js +++ b/src/devices.js @@ -77,17 +77,16 @@ function installStep(step) { } ) .then(() => { + global.mainEvent.emit("user:write:working", "particles"); + global.mainEvent.emit("user:write:under", "Verifying download"); + global.mainEvent.emit("user:write:progress", 0); + global.mainEvent.emit("user:write:speed", 0); setTimeout(() => { - global.mainEvent.emit("user:write:working", "particles"); - global.mainEvent.emit("user:write:under", "Verifying download"); - global.mainEvent.emit("user:write:progress", 0); - global.mainEvent.emit("user:write:speed", 0); resolve(); }, 1000); }) .catch(reject); }); - break; case "adb:format": return new Promise(function(resolve, reject) { global.mainEvent.emit("user:write:working", "particles"); @@ -110,7 +109,6 @@ function installStep(step) { }) .catch(reject); }); - break; case "adb:reboot": return new Promise(function(resolve, reject) { global.mainEvent.emit("user:write:working", "particles"); @@ -124,7 +122,6 @@ function installStep(step) { .then(resolve) .catch(reject); }); - break; case "fastboot:flash": return new Promise(function(resolve, reject) { global.mainEvent.emit("user:write:working", "particles"); @@ -133,11 +130,6 @@ function installStep(step) { "user:write:under", "Flashing firmware partitions using fastboot" ); - utils.log.debug( - JSON.stringify( - addPathToFiles(step.flash, global.installProperties.device) - ) - ); fastboot .flashArray( addPathToFiles(step.flash, global.installProperties.device) @@ -145,7 +137,6 @@ function installStep(step) { .then(resolve) .catch(reject); }); - break; case "fastboot:erase": return new Promise(function(resolve, reject) { global.mainEvent.emit("user:write:working", "particles"); @@ -159,7 +150,6 @@ function installStep(step) { .then(resolve) .catch(reject); }); - break; case "fastboot:boot": return new Promise(function(resolve, reject) { global.mainEvent.emit("user:write:working", "particles"); @@ -181,7 +171,6 @@ function installStep(step) { .then(resolve) .catch(reject); }); - break; case "systemimage": return new Promise(function(resolve, reject) { systemImage @@ -194,7 +183,6 @@ function installStep(step) { .then(resolve) .catch(reject); }); - break; case "fastboot:update": return new Promise(function(resolve, reject) { global.mainEvent.emit("user:write:working", "particles"); @@ -216,7 +204,6 @@ function installStep(step) { .then(resolve) .catch(reject); }); - break; case "fastboot:reboot_bootloader": return new Promise(function(resolve, reject) { global.mainEvent.emit("user:write:working", "particles"); @@ -227,7 +214,6 @@ function installStep(step) { .then(resolve) .catch(reject); }); - break; case "fastboot:reboot": return new Promise(function(resolve, reject) { global.mainEvent.emit("user:write:working", "particles"); @@ -238,7 +224,6 @@ function installStep(step) { .then(resolve) .catch(reject); }); - break; case "fastboot:continue": return new Promise(function(resolve, reject) { global.mainEvent.emit("user:write:working", "particles"); @@ -249,7 +234,6 @@ function installStep(step) { .then(resolve) .catch(reject); }); - break; case "user_action": return new Promise(function(resolve, reject) { global.mainEvent.emit( @@ -258,7 +242,6 @@ function installStep(step) { resolve ); }); - break; default: throw "error: unrecognized step type: " + step.type; } @@ -279,6 +262,9 @@ function assembleInstallSteps(steps) { resolve(); } else { utils.log.debug("running step: " + JSON.stringify(step)); + function restartInstall() { + install(steps); + } function runStep() { installStep(step) .then(() => { @@ -300,9 +286,7 @@ function assembleInstallSteps(steps) { error && error.includes("lock") ) { - global.mainEvent.emit("user:oem-lock", () => { - install(steps); - }); + global.mainEvent.emit("user:oem-lock", runStep); } else { if ( error && @@ -311,11 +295,19 @@ function assembleInstallSteps(steps) { error.includes("No such device") || error.includes("connection lost")) ) { - mainEvent.emit("user:connection-lost", runStep); + mainEvent.emit( + "user:connection-lost", + step.resumable ? runStep : restartInstall + ); } else if (error && error.includes("Killed")) { reject(); // Used for exiting the installer } else { - utils.errorToUser(error, step.type); + utils.errorToUser( + error, + step.type, + restartInstall, + runStep + ); } } }); diff --git a/src/html/index.pug b/src/html/index.pug index 726447b3..8ed5ea3a 100644 --- a/src/html/index.pug +++ b/src/html/index.pug @@ -4,7 +4,7 @@ html link(rel='stylesheet', href='../../node_modules/bootstrap/dist/css/bootstrap.min.css') link(rel='stylesheet', href='../css/style.css') body - include scripts/root + script(src="scripts/root.js") .header.is-over h3#header-text.text-muted.installer UBports Installer (#{global.packageInfo.version}) button#help.help-button.btn.btn-primary.is-over Report a bug @@ -46,10 +46,9 @@ html include modals/no-network // --- Scripts --- // Animated loading screen - include scripts/particleground - include scripts/start + script(src="scripts/particleground.js") + script(src="scripts/start.js") // UI-related event management - include scripts/ui + script(src="scripts/ui.js") // Functionality-related event management - include scripts/main - include scripts/dots + script(src="scripts/dots.js") diff --git a/src/html/modals/connection-lost.pug b/src/html/modals/connection-lost.pug index 4599cf2e..7b5a6a10 100644 --- a/src/html/modals/connection-lost.pug +++ b/src/html/modals/connection-lost.pug @@ -11,4 +11,8 @@ b | If this continues to happen, you might want to try using a different USB cable. Old cables tend to become less reliable. Please try using a different USB cable and do not touch the device during the installation, unless you are prompted to do so. .modal-footer - button#btn-reconnect.btn.btn-primary(type='button', data-dismiss='modal') Try again + button#btn-reconnect.btn.btn-primary(type='button', data-dismiss='modal', onclick='ipcRenderer.send("reconnect")') Try again + script. + ipcRenderer.on("user:connection-lost", () => { + modals.show("connection-lost"); + }); diff --git a/src/html/modals/error.pug b/src/html/modals/error.pug index 352651f5..d3cc8cf2 100644 --- a/src/html/modals/error.pug +++ b/src/html/modals/error.pug @@ -17,6 +17,24 @@ p If you need help, you can join UBports' support channels on #[a(onclick="shell.openExternal('https://t.me/WelcomePlus')") telegram] or #[a(onclick="shell.openExternal('https://matrix.to/#/!KwdniMNeTmClpgHkND:matrix.org?via=matrix.org&via=ubports.chat&via=disroot.org')") matrix] or ask a question #[a(onclick="shell.openExternal('https://forums.ubports.com')") in the forum] or on #[a(onclick="shell.openExternal('https://askubuntu.com')") askubuntu]. As a last resort, we also have #[a(onclick="shell.openExternal('https://devices.ubuntu-touch.io')") manual installation instructions for every device], that you can follow if you want to install without using the UBports Installer. .modal-footer - button.btn.btn-default(type='button', hidden='hidden', data-dismiss='modal', onclick="restartInstaller()") Try again - button.btn.btn-default(type='button', hidden='hidden', data-dismiss='modal', onclick="ignoreError()") Ignore - button#btn-bugreport.btn.btn-primary(type='button') Report a bug + button.btn.btn-default(type='button', hidden='hidden', data-dismiss='modal', onclick='ipcRenderer.send("user:error:reply", "restart")') Try again + button.btn.btn-default(type='button', hidden='hidden', data-dismiss='modal', onclick='ipcRenderer.send("user:error:reply", "ignore")') Ignore + button#btn-bugreport.btn.btn-primary(type='button', onclick='ipcRenderer.send("user:error:reply", "bugreport")') Report a bug + script. + ipcRenderer.on("user:error", (event, error, restart, ignore) => { + if(global.packageInfo.updateAvailable) { + $("#not-latest-stable").show(); + if (global.packageInfo.isSnap) { + $("#snap-update-instructions-error").show(); + } else { + $("#generic-update-instructions-error").show(); + } + } + $("#error-body").text(error); + $("#error-modal").modal("show"); + }); + + // Catch all unhandled errors in rendering process + window.onerror = (err, url, line) => { + ipcRenderer.send("renderer:error", err + " (MainRenderer:" + line + ")"); + } diff --git a/src/html/modals/low-power.pug b/src/html/modals/low-power.pug index 32fce5df..181f9191 100644 --- a/src/html/modals/low-power.pug +++ b/src/html/modals/low-power.pug @@ -12,3 +12,7 @@ | Please let your device charge for a while and try again. .modal-footer button.btn.btn-default(type='button', data-dismiss='modal', onclick="ipcRenderer.send('restart');") Try again + script. + ipcRenderer.on("user:low-power", (callback) => { + modals.show("low-power"); + }); diff --git a/src/html/modals/new-update.pug b/src/html/modals/new-update.pug index e58ff08d..ee764af7 100644 --- a/src/html/modals/new-update.pug +++ b/src/html/modals/new-update.pug @@ -12,3 +12,13 @@ .modal-footer button.btn.btn-default(type='button', data-dismiss='modal') Dismiss button#btn-update-installer.btn.btn-primary(type='button', onclick="shell.openExternal('https://github.com/ubports/ubports-installer/releases/latest')") Download + script. + ipcRenderer.on("user:update-available", () => { + if (global.packageInfo.isSnap) { + $("#snap-update-instructions").show(); + $("#btn-update-installer").hide(); + } else { + $("#generic-update-instructions").show(); + } + modals.show('new-update'); + }); diff --git a/src/html/modals/no-network.pug b/src/html/modals/no-network.pug index 8baacf6b..99c6fffd 100644 --- a/src/html/modals/no-network.pug +++ b/src/html/modals/no-network.pug @@ -10,3 +10,7 @@ | The installer could not connect to UBports' servers to download the devices list. Are you connected to the internet? .modal-footer button.btn.btn-default(type='button', data-dismiss='modal', onclick="ipcRenderer.send('restart');") Try again + script. + ipcRenderer.on("user:no-network", () => { + modals.show('no-network'); + }); diff --git a/src/html/modals/oem-lock.pug b/src/html/modals/oem-lock.pug index fa8765ea..bb4206de 100644 --- a/src/html/modals/oem-lock.pug +++ b/src/html/modals/oem-lock.pug @@ -18,3 +18,20 @@ button#btn-exit.btn.btn-default(type='button', data-dismiss='modal') Abort button#btn-unlock.btn.btn-primary(type='button') Unlock i#unlock-prog.fa.fa-cog.fa-spin.fa-2x.fa-fw.hidden(hidden='hidden') + script. + ipcRenderer.on("user:oem-lock", (event) => { + modals.show('oem-lock'); + }); + + $("#btn-unlock").click(() => { + event.sender.send("user:oem-lock:ok"); + modals.hide('oem-lock'); + $("#btn-unlock").attr("disabled", true); + $("#btn-exit").attr("disabled", true); + $("#unlock-prog").removeClass("hidden"); + }); + + $("#btn-exit").click(() => { + var window = remote.getCurrentWindow(); + window.close(); + }); diff --git a/src/html/modals/options.pug b/src/html/modals/options.pug index 89f0aa1f..bba3b4b1 100644 --- a/src/html/modals/options.pug +++ b/src/html/modals/options.pug @@ -76,11 +76,14 @@ } else { ipcRenderer.send("option", option.var, $("#options-" + option.var).val()); } + modals.show('install'); }); } let optionsAdded = false; ipcRenderer.on("user:configure", (event, osInstructs) => { + views.show("working", "particles"); + footer.underText.set("Please Configure the installation"); modals.show("options"); if (!optionsAdded) { optionsAdded = true; diff --git a/src/html/modals/select-device.pug b/src/html/modals/select-device.pug index 1fcda5e8..bcf29cbb 100644 --- a/src/html/modals/select-device.pug +++ b/src/html/modals/select-device.pug @@ -15,3 +15,7 @@ .modal-footer button.btn.btn-default(type='button', data-dismiss='modal') Close button#btn-select-device.btn.btn-primary(type='button', data-dismiss='modal') Select + script. + ipcRenderer.on("user:os", () => { + modals.hide("select-device"); + }); diff --git a/src/html/modals/windows-drivers.pug b/src/html/modals/windows-drivers.pug index f9f14a40..013819cf 100644 --- a/src/html/modals/windows-drivers.pug +++ b/src/html/modals/windows-drivers.pug @@ -18,3 +18,7 @@ .modal-footer button.btn.btn-default(type='button', data-dismiss='modal') Dismiss button#btn-driver-never-ask.btn.btn-primary(type='button', data-dismiss='modal', onclick="localStorage.setItem('neverAskForWindowsDrivers', 'true');") Don't ask me again + script. + if (process.platform === "win32" && !localStorage.getItem('neverAskForWindowsDrivers')) { + modals.show('windows-drivers'); + } \ No newline at end of file diff --git a/src/html/scripts/dots.js b/src/html/scripts/dots.js new file mode 100644 index 00000000..413415b9 --- /dev/null +++ b/src/html/scripts/dots.js @@ -0,0 +1,5 @@ +const dots = window.setInterval(function() { + var wait = $("[id=wait-dot]"); + if (wait.text().length > 4) wait.text(""); + else wait.append("."); +}, 400); diff --git a/src/html/scripts/dots.pug b/src/html/scripts/dots.pug deleted file mode 100644 index 8ea0d2ee..00000000 --- a/src/html/scripts/dots.pug +++ /dev/null @@ -1,8 +0,0 @@ -script. - const dots = window.setInterval( function() { - var wait = $("[id=wait-dot]"); - if ( wait.text().length > 4 ) - wait.text(""); - else - wait.append("."); - }, 400); diff --git a/src/html/scripts/main.pug b/src/html/scripts/main.pug deleted file mode 100644 index b353fed3..00000000 --- a/src/html/scripts/main.pug +++ /dev/null @@ -1,142 +0,0 @@ -script. - // CATCH ANY ERRORS! - var onErr = (err) => { - if(global.packageInfo.updateAvailable) { - $("#not-latest-stable").show(); - if (global.packageInfo.isSnap) { - $("#snap-update-instructions-error").show(); - } else { - $("#generic-update-instructions-error").show(); - } - } - $("#error-body").text(err); - $("#error-modal").modal("show"); - } - - window.onerror = (err, url, line) => { - onErr(err+" (MainRenderer:"+line+")"); - } - - ipcRenderer.on("user:error", (event, err) => { onErr(err); }); - - ipcRenderer.on("user:write:working", (e, animation) => { - views.show("working", animation); - }); - - ipcRenderer.on("user:connection-lost", (e, callback) => { - modals.show("connection-lost"); - $("#btn-reconnect").click(callback); - }); - - ipcRenderer.on("user:low-power", (callback) => { - modals.show("low-power"); - }); - - var ignoreError = () => { - ipcRenderer.send('error_ignored'); - } - - var restartInstaller = () => { - ipcRenderer.send('restart'); - } - - ipcRenderer.on("user:oem-lock", (event) => { - modals.show('oem-lock'); - $("#btn-unlock").click(() => { - event.sender.send("user:oem-lock:ok"); - modals.hide('oem-lock'); - $("#btn-unlock").attr("disabled", true); - $("#btn-exit").attr("disabled", true); - $("#unlock-prog").removeClass("hidden"); - }); - }); - - ipcRenderer.on("user:no-network", () => { - modals.show('no-network'); - }); - - ipcRenderer.on("user:write:speed", (e, speed) => { - footer.speedText.set(speed); - }); - - ipcRenderer.on("user:write:progress", (e, length) => { - if(length >= 100) { - length=100; - } - $("#progress").show(); - $("#progress").width(length.toString()+"%"); - }); - - ipcRenderer.on("user:write:done", () => { - if (global.installProperties.cli) { - remote.getCurrentWindow().close(); - } else { - views.show("done"); - $("#progress").width("0%"); - } - }); - - ipcRenderer.on("user:write:status", (e, status, waitDots) => { - footer.topText.set(status, waitDots); - }); - - ipcRenderer.on("user:write:under", (e, status) => { - footer.underText.set(status, true); - }); - - ipcRenderer.on("user:device-unsupported", (event, device) => { - footer.topText.set("Device not supported"); - footer.underText.set("The device " + device + " is not supported"); - $("[id=your-device]").text(device); - views.show("not-supported"); - }); - - ipcRenderer.on("user:os", (event, installConfig, osSelects) => { - global.installConfig = installConfig; - global.installConfig.os_to_install = undefined; - $("#options-os").append(osSelects); - $("#your-ubp-device").text(installConfig.name+" ("+installConfig.codename+")"); - $("#your-ubp-device").click(() => { - shell.openExternal("https://devices.ubuntu-touch.io/device/" + installConfig.codename); - }); - modals.hide("select-device"); - views.show("select-os"); - }); - - ipcRenderer.on("user:action", (event, action) => { - views.show("user-action"); - $("#user-action-title").text(action.title) - $("#user-action-description").text(action.description) - - if (action.image) $("#user-action-image").attr("src", "../img/" + action.image + ".jpg"); - else $("#user-action-image").attr("src", "../screens/Screen6.jpg"); - - if (action.button) { - $("#user-action-button").one("click", () => { - event.sender.send("action:completed"); - }); - $("#user-action-button").show(); - } else { - $("#user-action-button").hide(); - } - }); - - views.show("working", "particles"); - - ipcRenderer.on("device:wait:device-selects-ready", (event, deviceSelects) => { - footer.topText.set("Waiting for device", true); - footer.underText.set("Please connect your device with a USB cable"); - if (!remote.getGlobal("installProperties").device) { - // if the device is not yet set (i.e. from a cli argument), prompt the user - $("#device-select").append(deviceSelects); - views.show("wait-for-device"); - // Button to confirm device selection - $("#btn-select-device").click(() => { - var device = $("#device-select").find(":selected").attr("name"); - ipcRenderer.send("device:selected", device); - }); - } else { - // if the device is set, just return the device:selected event - ipcRenderer.send("device:selected", remote.getGlobal("installProperties").device); - } - }); diff --git a/src/html/scripts/particleground.js b/src/html/scripts/particleground.js new file mode 100644 index 00000000..0319e370 --- /dev/null +++ b/src/html/scripts/particleground.js @@ -0,0 +1,362 @@ +/*! + * Particleground + * + * @author Jonathan Nicol - @mrjnicol + * @version 1.1.0 + * @description Creates a canvas based particle system background + * + * Inspired by http://requestlab.fr/ and http://disruptivebydesign.com/ + */ +!(function(a, b) { + "use strict"; + function c(a) { + a = a || {}; + for (var b = 1; b < arguments.length; b++) { + var c = arguments[b]; + if (c) + for (var d in c) + c.hasOwnProperty(d) && + ("object" == typeof c[d] ? deepExtend(a[d], c[d]) : (a[d] = c[d])); + } + return a; + } + function d(d, g) { + function h() { + if (y) { + (r = b.createElement("canvas")), + (r.className = "pg-canvas"), + (r.style.display = "block"), + d.insertBefore(r, d.firstChild), + (s = r.getContext("2d")), + i(); + for ( + var c = Math.round((r.width * r.height) / g.density), e = 0; + c > e; + e++ + ) { + var f = new n(); + f.setStackPos(e), z.push(f); + } + a.addEventListener( + "resize", + function() { + k(); + }, + !1 + ), + b.addEventListener( + "mousemove", + function(a) { + (A = a.pageX), (B = a.pageY); + }, + !1 + ), + D && + !C && + a.addEventListener( + "deviceorientation", + function() { + (F = Math.min(Math.max(-event.beta, -30), 30)), + (E = Math.min(Math.max(-event.gamma, -30), 30)); + }, + !0 + ), + j(), + q("onInit"); + } + } + function i() { + (r.width = d.offsetWidth), + (r.height = d.offsetHeight), + (s.fillStyle = g.dotColor), + (s.strokeStyle = g.lineColor), + (s.lineWidth = g.lineWidth); + } + function j() { + if (y) { + (u = a.innerWidth), + (v = a.innerHeight), + s.clearRect(0, 0, r.width, r.height); + for (var b = 0; b < z.length; b++) z[b].updatePosition(); + for (var b = 0; b < z.length; b++) z[b].draw(); + G || (t = requestAnimationFrame(j)); + } + } + function k() { + i(); + for ( + var a = d.offsetWidth, b = d.offsetHeight, c = z.length - 1; + c >= 0; + c-- + ) + (z[c].position.x > a || z[c].position.y > b) && z.splice(c, 1); + var e = Math.round((r.width * r.height) / g.density); + if (e > z.length) + for (; e > z.length; ) { + var f = new n(); + z.push(f); + } + else e < z.length && z.splice(e); + for (c = z.length - 1; c >= 0; c--) z[c].setStackPos(c); + } + function l() { + G = !0; + } + function m() { + (G = !1), j(); + } + function n() { + switch ( + (this.stackPos, + (this.active = !0), + (this.layer = Math.ceil(3 * Math.random())), + (this.parallaxOffsetX = 0), + (this.parallaxOffsetY = 0), + (this.position = { + x: Math.ceil(Math.random() * r.width), + y: Math.ceil(Math.random() * r.height) + }), + (this.speed = {}), + g.directionX) + ) { + case "left": + this.speed.x = +( + -g.maxSpeedX + + Math.random() * g.maxSpeedX - + g.minSpeedX + ).toFixed(2); + break; + case "right": + this.speed.x = +(Math.random() * g.maxSpeedX + g.minSpeedX).toFixed( + 2 + ); + break; + default: + (this.speed.x = +( + -g.maxSpeedX / 2 + + Math.random() * g.maxSpeedX + ).toFixed(2)), + (this.speed.x += this.speed.x > 0 ? g.minSpeedX : -g.minSpeedX); + } + switch (g.directionY) { + case "up": + this.speed.y = +( + -g.maxSpeedY + + Math.random() * g.maxSpeedY - + g.minSpeedY + ).toFixed(2); + break; + case "down": + this.speed.y = +(Math.random() * g.maxSpeedY + g.minSpeedY).toFixed( + 2 + ); + break; + default: + (this.speed.y = +( + -g.maxSpeedY / 2 + + Math.random() * g.maxSpeedY + ).toFixed(2)), + (this.speed.x += this.speed.y > 0 ? g.minSpeedY : -g.minSpeedY); + } + } + function o(a, b) { + return b ? void (g[a] = b) : g[a]; + } + function p() { + console.log("destroy"), + r.parentNode.removeChild(r), + q("onDestroy"), + f && f(d).removeData("plugin_" + e); + } + function q(a) { + void 0 !== g[a] && g[a].call(d); + } + var r, + s, + t, + u, + v, + w, + x, + y = !!b.createElement("canvas").getContext, + z = [], + A = 0, + B = 0, + C = !navigator.userAgent.match( + /(iPhone|iPod|iPad|Android|BlackBerry|BB10|mobi|tablet|opera mini|nexus 7)/i + ), + D = !!a.DeviceOrientationEvent, + E = 0, + F = 0, + G = !1; + return ( + (g = c({}, a[e].defaults, g)), + (n.prototype.draw = function() { + s.beginPath(), + s.arc( + this.position.x + this.parallaxOffsetX, + this.position.y + this.parallaxOffsetY, + g.particleRadius / 2, + 0, + 2 * Math.PI, + !0 + ), + s.closePath(), + s.fill(), + s.beginPath(); + for (var a = z.length - 1; a > this.stackPos; a--) { + var b = z[a], + c = this.position.x - b.position.x, + d = this.position.y - b.position.y, + e = Math.sqrt(c * c + d * d).toFixed(2); + e < g.proximity && + (s.moveTo( + this.position.x + this.parallaxOffsetX, + this.position.y + this.parallaxOffsetY + ), + g.curvedLines + ? s.quadraticCurveTo( + Math.max(b.position.x, b.position.x), + Math.min(b.position.y, b.position.y), + b.position.x + b.parallaxOffsetX, + b.position.y + b.parallaxOffsetY + ) + : s.lineTo( + b.position.x + b.parallaxOffsetX, + b.position.y + b.parallaxOffsetY + )); + } + s.stroke(), s.closePath(); + }), + (n.prototype.updatePosition = function() { + if (g.parallax) { + if (D && !C) { + var a = (u - 0) / 60; + w = (E - -30) * a + 0; + var b = (v - 0) / 60; + x = (F - -30) * b + 0; + } else (w = A), (x = B); + (this.parallaxTargX = + (w - u / 2) / (g.parallaxMultiplier * this.layer)), + (this.parallaxOffsetX += + (this.parallaxTargX - this.parallaxOffsetX) / 10), + (this.parallaxTargY = + (x - v / 2) / (g.parallaxMultiplier * this.layer)), + (this.parallaxOffsetY += + (this.parallaxTargY - this.parallaxOffsetY) / 10); + } + var c = d.offsetWidth, + e = d.offsetHeight; + switch (g.directionX) { + case "left": + this.position.x + this.speed.x + this.parallaxOffsetX < 0 && + (this.position.x = c - this.parallaxOffsetX); + break; + case "right": + this.position.x + this.speed.x + this.parallaxOffsetX > c && + (this.position.x = 0 - this.parallaxOffsetX); + break; + default: + (this.position.x + this.speed.x + this.parallaxOffsetX > c || + this.position.x + this.speed.x + this.parallaxOffsetX < 0) && + (this.speed.x = -this.speed.x); + } + switch (g.directionY) { + case "up": + this.position.y + this.speed.y + this.parallaxOffsetY < 0 && + (this.position.y = e - this.parallaxOffsetY); + break; + case "down": + this.position.y + this.speed.y + this.parallaxOffsetY > e && + (this.position.y = 0 - this.parallaxOffsetY); + break; + default: + (this.position.y + this.speed.y + this.parallaxOffsetY > e || + this.position.y + this.speed.y + this.parallaxOffsetY < 0) && + (this.speed.y = -this.speed.y); + } + (this.position.x += this.speed.x), (this.position.y += this.speed.y); + }), + (n.prototype.setStackPos = function(a) { + this.stackPos = a; + }), + h(), + { option: o, destroy: p, start: m, pause: l } + ); + } + var e = "particleground", + f = a.jQuery; + (a[e] = function(a, b) { + return new d(a, b); + }), + (a[e].defaults = { + minSpeedX: 0.1, + maxSpeedX: 0.7, + minSpeedY: 0.1, + maxSpeedY: 0.7, + directionX: "center", + directionY: "center", + density: 1e4, + dotColor: "#666666", + lineColor: "#666666", + particleRadius: 7, + lineWidth: 1, + curvedLines: !1, + proximity: 100, + parallax: !0, + parallaxMultiplier: 5, + onInit: function() {}, + onDestroy: function() {} + }), + f && + (f.fn[e] = function(a) { + if ("string" == typeof arguments[0]) { + var b, + c = arguments[0], + g = Array.prototype.slice.call(arguments, 1); + return ( + this.each(function() { + f.data(this, "plugin_" + e) && + "function" == typeof f.data(this, "plugin_" + e)[c] && + (b = f.data(this, "plugin_" + e)[c].apply(this, g)); + }), + void 0 !== b ? b : this + ); + } + return "object" != typeof a && a + ? void 0 + : this.each(function() { + f.data(this, "plugin_" + e) || + f.data(this, "plugin_" + e, new d(this, a)); + }); + }); +})(window, document), + /** + * requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel + * @see: http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + * @see: http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating + * @license: MIT license + */ (function() { + for ( + var a = 0, b = ["ms", "moz", "webkit", "o"], c = 0; + c < b.length && !window.requestAnimationFrame; + ++c + ) + (window.requestAnimationFrame = window[b[c] + "RequestAnimationFrame"]), + (window.cancelAnimationFrame = + window[b[c] + "CancelAnimationFrame"] || + window[b[c] + "CancelRequestAnimationFrame"]); + window.requestAnimationFrame || + (window.requestAnimationFrame = function(b) { + var c = new Date().getTime(), + d = Math.max(0, 16 - (c - a)), + e = window.setTimeout(function() { + b(c + d); + }, d); + return (a = c + d), e; + }), + window.cancelAnimationFrame || + (window.cancelAnimationFrame = function(a) { + clearTimeout(a); + }); + })(); diff --git a/src/html/scripts/particleground.pug b/src/html/scripts/particleground.pug deleted file mode 100644 index cde8d45a..00000000 --- a/src/html/scripts/particleground.pug +++ /dev/null @@ -1,17 +0,0 @@ -script. - /*! - * Particleground - * - * @author Jonathan Nicol - @mrjnicol - * @version 1.1.0 - * @description Creates a canvas based particle system background - * - * Inspired by http://requestlab.fr/ and http://disruptivebydesign.com/ - */ - !function(a,b){"use strict";function c(a){a=a||{};for(var b=1;be;e++){var f=new n;f.setStackPos(e),z.push(f)}a.addEventListener("resize",function(){k()},!1),b.addEventListener("mousemove",function(a){A=a.pageX,B=a.pageY},!1),D&&!C&&a.addEventListener("deviceorientation",function(){F=Math.min(Math.max(-event.beta,-30),30),E=Math.min(Math.max(-event.gamma,-30),30)},!0),j(),q("onInit")}}function i(){r.width=d.offsetWidth,r.height=d.offsetHeight,s.fillStyle=g.dotColor,s.strokeStyle=g.lineColor,s.lineWidth=g.lineWidth}function j(){if(y){u=a.innerWidth,v=a.innerHeight,s.clearRect(0,0,r.width,r.height);for(var b=0;b=0;c--)(z[c].position.x>a||z[c].position.y>b)&&z.splice(c,1);var e=Math.round(r.width*r.height/g.density);if(e>z.length)for(;e>z.length;){var f=new n;z.push(f)}else e=0;c--)z[c].setStackPos(c)}function l(){G=!0}function m(){G=!1,j()}function n(){switch(this.stackPos,this.active=!0,this.layer=Math.ceil(3*Math.random()),this.parallaxOffsetX=0,this.parallaxOffsetY=0,this.position={x:Math.ceil(Math.random()*r.width),y:Math.ceil(Math.random()*r.height)},this.speed={},g.directionX){case"left":this.speed.x=+(-g.maxSpeedX+Math.random()*g.maxSpeedX-g.minSpeedX).toFixed(2);break;case"right":this.speed.x=+(Math.random()*g.maxSpeedX+g.minSpeedX).toFixed(2);break;default:this.speed.x=+(-g.maxSpeedX/2+Math.random()*g.maxSpeedX).toFixed(2),this.speed.x+=this.speed.x>0?g.minSpeedX:-g.minSpeedX}switch(g.directionY){case"up":this.speed.y=+(-g.maxSpeedY+Math.random()*g.maxSpeedY-g.minSpeedY).toFixed(2);break;case"down":this.speed.y=+(Math.random()*g.maxSpeedY+g.minSpeedY).toFixed(2);break;default:this.speed.y=+(-g.maxSpeedY/2+Math.random()*g.maxSpeedY).toFixed(2),this.speed.x+=this.speed.y>0?g.minSpeedY:-g.minSpeedY}}function o(a,b){return b?void(g[a]=b):g[a]}function p(){console.log("destroy"),r.parentNode.removeChild(r),q("onDestroy"),f&&f(d).removeData("plugin_"+e)}function q(a){void 0!==g[a]&&g[a].call(d)}var r,s,t,u,v,w,x,y=!!b.createElement("canvas").getContext,z=[],A=0,B=0,C=!navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|BB10|mobi|tablet|opera mini|nexus 7)/i),D=!!a.DeviceOrientationEvent,E=0,F=0,G=!1;return g=c({},a[e].defaults,g),n.prototype.draw=function(){s.beginPath(),s.arc(this.position.x+this.parallaxOffsetX,this.position.y+this.parallaxOffsetY,g.particleRadius/2,0,2*Math.PI,!0),s.closePath(),s.fill(),s.beginPath();for(var a=z.length-1;a>this.stackPos;a--){var b=z[a],c=this.position.x-b.position.x,d=this.position.y-b.position.y,e=Math.sqrt(c*c+d*d).toFixed(2);ec&&(this.position.x=0-this.parallaxOffsetX);break;default:(this.position.x+this.speed.x+this.parallaxOffsetX>c||this.position.x+this.speed.x+this.parallaxOffsetX<0)&&(this.speed.x=-this.speed.x)}switch(g.directionY){case"up":this.position.y+this.speed.y+this.parallaxOffsetY<0&&(this.position.y=e-this.parallaxOffsetY);break;case"down":this.position.y+this.speed.y+this.parallaxOffsetY>e&&(this.position.y=0-this.parallaxOffsetY);break;default:(this.position.y+this.speed.y+this.parallaxOffsetY>e||this.position.y+this.speed.y+this.parallaxOffsetY<0)&&(this.speed.y=-this.speed.y)}this.position.x+=this.speed.x,this.position.y+=this.speed.y},n.prototype.setStackPos=function(a){this.stackPos=a},h(),{option:o,destroy:p,start:m,pause:l}}var e="particleground",f=a.jQuery;a[e]=function(a,b){return new d(a,b)},a[e].defaults={minSpeedX:.1,maxSpeedX:.7,minSpeedY:.1,maxSpeedY:.7,directionX:"center",directionY:"center",density:1e4,dotColor:"#666666",lineColor:"#666666",particleRadius:7,lineWidth:1,curvedLines:!1,proximity:100,parallax:!0,parallaxMultiplier:5,onInit:function(){},onDestroy:function(){}},f&&(f.fn[e]=function(a){if("string"==typeof arguments[0]){var b,c=arguments[0],g=Array.prototype.slice.call(arguments,1);return this.each(function(){f.data(this,"plugin_"+e)&&"function"==typeof f.data(this,"plugin_"+e)[c]&&(b=f.data(this,"plugin_"+e)[c].apply(this,g))}),void 0!==b?b:this}return"object"!=typeof a&&a?void 0:this.each(function(){f.data(this,"plugin_"+e)||f.data(this,"plugin_"+e,new d(this,a))})})}(window,document),/** - * requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel - * @see: http://paulirish.com/2011/requestanimationframe-for-smart-animating/ - * @see: http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating - * @license: MIT license - */ - function(){for(var a=0,b=["ms","moz","webkit","o"],c=0;c { + $("." + from).hide(); + $("." + to).show(); +}; + +const hideAll = id => { + $("." + id).hide(); +}; + +const showAll = id => { + $("." + id).show(); +}; + +const show = (cat, id) => { + hideAll(cat); + $("#" + cat + "-" + id).show(); +}; + +const setText = (cat, id, text) => { + $("." + cat + "-" + id).text(text); +}; + +const animations = { + hideAll: () => { + $("#particles-foreground").hide(); + $("#particles-background").hide(); + $("#push-animation").hide(); + $("#download-animation").hide(); + }, + particles: () => { + $("#particles-foreground").show(); + $("#particles-background").show(); + $("#push-animation").hide(); + $("#download-animation").hide(); + }, + download: () => { + $("#download-animation").show(); + $("#push-animation").hide(); + $("#particles-foreground").hide(); + $("#particles-background").hide(); + }, + push: () => { + $("#push-animation").show(); + $("#download-animation").hide(); + $("#particles-foreground").hide(); + $("#particles-background").hide(); + } +}; + +const views = { + hideAll: () => hideAll("views"), + show: (id, animation) => { + if (id != "working") { + if (id == "done") { + $(".ubp-robot").addClass("ubp-robot-side"); + $(".ubp-robot").removeClass("ubp-robot-foot"); + } else { + $(".ubp-robot").removeClass("ubp-robot-side"); + $(".ubp-robot").addClass("ubp-robot-foot"); + } + animations.hideAll(); + show("views", id); + return; + } else { + $(".ubp-robot").removeClass("ubp-robot-side"); + $(".ubp-robot").removeClass("ubp-robot-foot"); + show("views", "working"); + switch (animation) { + case "particles": + animations.particles(); + break; + case "download": + animations.download(); + break; + case "push": + animations.push(); + break; + default: + animations.hideAll(); + } + } + } +}; + +const userText = { + set: (id, text) => setText("user", id, text), + remove: id => setText("user", id, "") +}; + +const footer = { + topText: { + set: (text, dots) => { + if (dots) $("#wait-dot").show(); + else $("#wait-dot").hide(); + return $("#footer-top").text(text); + } + }, + underText: { + set: text => { + return $("#footer-bottom").text(text); + } + }, + speedText: { + set: text => { + if (text) return $("#footer-speed").text(" at " + text + " MB/s"); + else return $("#footer-speed").text(""); + } + } +}; + +const modals = { + show: modal => { + $("#" + modal + "-modal").modal("show"); + }, + hide: modal => { + $("#" + modal + "-modal").modal("hide"); + } +}; + +$("#help").click(() => { + ipcRenderer.send("createBugReport", "user-requested bug-report"); +}); + +$("#donate").click(() => { + shell.openExternal("https://ubports.com/donate"); +}); + +ipcRenderer.on("user:write:progress", (e, length) => { + if (length >= 100) { + length = 100; + } + $("#progress").show(); + $("#progress").width(length.toString() + "%"); +}); + +ipcRenderer.on("user:write:status", (e, status, waitDots) => { + footer.topText.set(status, waitDots); +}); + +ipcRenderer.on("user:write:under", (e, status) => { + footer.underText.set(status, true); +}); + +ipcRenderer.on("user:write:speed", (e, speed) => { + footer.speedText.set(speed); +}); + +views.show("working", "particles"); diff --git a/src/html/scripts/ui.pug b/src/html/scripts/ui.pug deleted file mode 100644 index a289da3e..00000000 --- a/src/html/scripts/ui.pug +++ /dev/null @@ -1,156 +0,0 @@ -script. - - const switchHide = (from, to) => { - $("."+from).hide(); - $("."+to).show(); - } - - const hideAll = (id) => { - $("."+id).hide(); - } - - const showAll = (id) => { - $("."+id).show(); - } - - const show = (cat, id) => { - hideAll(cat); - $("#"+cat+"-"+id).show(); - } - - const setText = (cat, id, text) => { - $("."+cat+"-"+id).text(text); - } - - const animations = { - hideAll: () => { - $("#particles-foreground").hide(); - $("#particles-background").hide(); - $("#push-animation").hide(); - $("#download-animation").hide(); - }, - particles: () => { - $("#particles-foreground").show(); - $("#particles-background").show(); - $("#push-animation").hide(); - $("#download-animation").hide(); - }, - download: () => { - $("#download-animation").show(); - $("#push-animation").hide(); - $("#particles-foreground").hide(); - $("#particles-background").hide(); - }, - push: () => { - $("#push-animation").show(); - $("#download-animation").hide(); - $("#particles-foreground").hide(); - $("#particles-background").hide(); - } - } - - const views = { - hideAll: () => hideAll("views"), - show: (id, animation) => { - if (id != "working"){ - if (id == "done") { - $(".ubp-robot").addClass("ubp-robot-side"); - $(".ubp-robot").removeClass("ubp-robot-foot"); - } else { - $(".ubp-robot").removeClass("ubp-robot-side"); - $(".ubp-robot").addClass("ubp-robot-foot"); - } - animations.hideAll(); - show("views", id); - return; - } else { - $(".ubp-robot").removeClass("ubp-robot-side"); - $(".ubp-robot").removeClass("ubp-robot-foot"); - show("views", "working"); - switch (animation) { - case "particles": - animations.particles() - break; - case "download": - animations.download() - break; - case "push": - animations.push() - break; - default: - animations.hideAll(); - } - } - } - } - - const userText = { - set: (id, text) => setText("user", id, text), - remove: id => setText("user", id, "") - } - - const footer = { - topText: { - set: (text, dots) => { - if (dots) $("#wait-dot").show() - else $("#wait-dot").hide() - return $("#footer-top").text(text) - } - }, - underText: { - set: (text) => { - return $("#footer-bottom").text(text) - } - }, - speedText: { - set: (text) => { - if (text) return $("#footer-speed").text(" at " + text + " MB/s"); - else return $("#footer-speed").text(""); - } - } - } - - const modals = { - show: modal => { - $('#'+modal+'-modal').modal('show'); - }, - hide: modal => { - $('#'+modal+'-modal').modal('hide'); - } - } - - $("#btn-bugreport").click(() => { - var title = $("#error-body").text(); - ipcRenderer.send("createBugReport", title); - }); - - $("#btn-exit").click(() => { - var window = remote.getCurrentWindow(); - window.close(); - }); - - $("#help").click(() => { - ipcRenderer.send("createBugReport", "user-requested bug-report"); - }); - - $("#donate").click(() => { - shell.openExternal("https://ubports.com/donate"); - }); - - $("#btn-options-close").click(() => { - modals.show('install'); - }); - - if (process.platform === "win32" && !localStorage.getItem('neverAskForWindowsDrivers')) { - modals.show('windows-drivers'); - } - - ipcRenderer.on("user:update-available", () => { - if (global.packageInfo.isSnap) { - $("#snap-update-instructions").show(); - $("#btn-update-installer").hide(); - } else { - $("#generic-update-instructions").show(); - } - modals.show('new-update'); - }); diff --git a/src/html/views/done.pug b/src/html/views/done.pug index a45f2518..b4eda0c3 100644 --- a/src/html/views/done.pug +++ b/src/html/views/done.pug @@ -12,7 +12,11 @@ | Development of Ubuntu Touch is driven by the #[a(onclick="shell.openExternal('https://ubports.com')") UBports Community]. Donate now to allow us to continue our mission! button.btn.btn-default(type='button', style='width: 49%; margin-bottom: 10px; margin-right: 5px', onclick="shell.openExternal('https://ubports.com/get-involved')") Get involved button.btn.btn-primary(type='button', style='width: 49%; margin-bottom: 10px;', onclick="shell.openExternal('https://ubports.com/donate')") Donate - //- Flash another temporarily disabled due to #963 - //- p - //- | Got more devices you want to flash? - //- button.btn.btn-info(type='button', style='width: 100%;', onclick="ipcRenderer.send('restart');") Flash another device! + p + | Got more devices you want to flash? + button.btn.btn-info(type='button', style='width: 100%;', onclick="ipcRenderer.send('restart');") Flash another device! + script. + ipcRenderer.on("user:write:done", () => { + views.show("done"); + $("#progress").width("0%"); + }); diff --git a/src/html/views/not-supported.pug b/src/html/views/not-supported.pug index eead2348..8e399112 100644 --- a/src/html/views/not-supported.pug +++ b/src/html/views/not-supported.pug @@ -19,3 +19,10 @@ p | You can try selecting your device manually, but please only do so if you're sure that your exact model is actually supported! You might also want to #[a(onclick="shell.openExternal('http://devices.ubuntu-touch.io')") file a bug]. button#btn-modal-select-device-unsupported.btn.btn-default(type='button', style='width: 100%;', onclick="modals.show('select-device');") Select device manually + script. + ipcRenderer.on("user:device-unsupported", (event, device) => { + footer.topText.set("Device not supported"); + footer.underText.set("The device " + device + " is not supported"); + $("[id=your-device]").text(device); + views.show("not-supported"); + }); diff --git a/src/html/views/select-os.pug b/src/html/views/select-os.pug index 56eb1f79..bef823a3 100644 --- a/src/html/views/select-os.pug +++ b/src/html/views/select-os.pug @@ -3,13 +3,31 @@ .col-xs-6 img(style='height: 350px; margin: auto; display: block;', src='../screens/Screen6.jpg') .col-xs-6(style='height: 100%') - h4.user-install-header(style='font-weight: bold;') Select your Operating System + h4.user-install-header#device-name(style='font-weight: bold;') p - | Your device: #[a#your-ubp-device] + | #[a#device-page-link about this device] | #[a#device-config view config file] p | What operating system do you want to install? form.form-horizontal .form-group + .col-xs-3 + label.control-label OS .col-xs-9 select#options-os.form-control.space button#btn-inst.btn.btn-primary(type='button', style='width: 100%; margin-top: 10px;', onclick="ipcRenderer.send(\"os:selected\", getElementById('options-os').selectedIndex); global.installConfig.os_to_install = getElementById('options-os').selectedIndex;") Install + script. + ipcRenderer.on("user:os", (event, installConfig, osSelects) => { + global.installConfig = installConfig; + global.installConfig.os_to_install = undefined; + footer.topText.set(installConfig.name+" ("+installConfig.codename+")"); + footer.underText.set("Please select an operating system for installation"); + $("#options-os").append(osSelects); + $("#device-name").text(installConfig.name+" ("+installConfig.codename+")"); + $("#device-page-link").click(() => { + shell.openExternal("https://devices.ubuntu-touch.io/device/" + installConfig.codename); + }); + $("#device-config").click(() => { + shell.openExternal("https://github.com/ubports/installer-configs/blob/master/v1/" + installConfig.codename + ".json"); + }); + views.show("select-os"); + }); diff --git a/src/html/views/user-action.pug b/src/html/views/user-action.pug index 7406fd49..ba4b7a46 100644 --- a/src/html/views/user-action.pug +++ b/src/html/views/user-action.pug @@ -6,3 +6,21 @@ h4#user-action-title(style='font-weight: bold;') p#user-action-description button#user-action-button.btn.btn-primary(hidden="false", type='button', style='width: 100%;') Continue + script. + ipcRenderer.on("user:action", (event, action) => { + views.show("user-action"); + $("#user-action-title").text(action.title) + $("#user-action-description").text(action.description) + + if (action.image) $("#user-action-image").attr("src", "../img/" + action.image + ".jpg"); + else $("#user-action-image").attr("src", "../screens/Screen6.jpg"); + + if (action.button) { + $("#user-action-button").one("click", () => { + event.sender.send("action:completed"); + }); + $("#user-action-button").show(); + } else { + $("#user-action-button").hide(); + } + }); \ No newline at end of file diff --git a/src/html/views/wait-for-device.pug b/src/html/views/wait-for-device.pug index 385d2753..e9fdeb6d 100644 --- a/src/html/views/wait-for-device.pug +++ b/src/html/views/wait-for-device.pug @@ -9,3 +9,21 @@ button#btn-modal-dev-mode.btn.btn-primary(type='button', style='width: 100%; margin-bottom: 10px;', onclick="modals.show('developer-mode-info');") How do I enable developer mode? p If your device is not detected automatically, you can select it manually to proceed. Please note that the UBports Installer will only work on #[a(onclick="shell.openExternal('http://devices.ubuntu-touch.io')") supported devices]. button#btn-modal-select-device.btn.btn-default(type='button', style='width: 100%;', onclick="modals.show('select-device');") Select device manually + script. + ipcRenderer.on("device:wait:device-selects-ready", (event, deviceSelects) => { + footer.topText.set("Waiting for device", true); + footer.underText.set("Please connect your device with a USB cable"); + if (!remote.getGlobal("installProperties").device) { + // if the device is not yet set (i.e. from a cli argument), prompt the user + $("#device-select").append(deviceSelects); + views.show("wait-for-device"); + // Button to confirm device selection + $("#btn-select-device").click(() => { + var device = $("#device-select").find(":selected").attr("name"); + ipcRenderer.send("device:selected", device); + }); + } else { + // if the device is set, just return the device:selected event + ipcRenderer.send("device:selected", remote.getGlobal("installProperties").device); + } + }); diff --git a/src/html/views/working.pug b/src/html/views/working.pug index 2e7cb464..3387b22c 100644 --- a/src/html/views/working.pug +++ b/src/html/views/working.pug @@ -4,3 +4,7 @@ .loader-line-mask .loader-line img.ubp-robot(width='100', src='../img/yumi.svg') +script. + ipcRenderer.on("user:write:working", (e, animation) => { + views.show("working", animation); + }); \ No newline at end of file diff --git a/src/main.js b/src/main.js index b162ea97..74998d6c 100755 --- a/src/main.js +++ b/src/main.js @@ -97,9 +97,7 @@ if (cli.file) { global.installProperties = { device: global.installConfig ? global.installConfig.codename : cli.device, - cli: cli.cli, - settings: cli.settings ? JSON.parse(cli.settings) : {}, - debug: cli.debug + settings: cli.settings ? JSON.parse(cli.settings) : {} }; if (utils.isSnap()) { @@ -149,11 +147,6 @@ ipcMain.on("restart", () => { mainEvent.emit("restart"); }); -// The user ignored an error -ipcMain.on("error_ignored", () => { - utils.log.debug("ERROR IGNORED"); -}); - // Begin install process ipcMain.on("install", () => { devices.install( @@ -173,6 +166,11 @@ ipcMain.on("device:selected", (event, device) => { mainEvent.emit("device", device); }); +// Error from the renderer process +ipcMain.on("renderer:error", (event, error) => { + mainEvent.emit("user:error", error); +}); + // The user selected an os ipcMain.on("os:selected", (event, osIndex) => { global.installProperties.osIndex = osIndex; @@ -193,22 +191,43 @@ ipcMain.on("option", (event, targetVar, value) => { //============================================================================== // Open the bugreporting tool -mainEvent.on("user:error", err => { +mainEvent.on("user:error", (error, restart, ignore) => { try { - if (mainWindow) mainWindow.webContents.send("user:error", err); - else process.exit(1); + if (mainWindow) { + mainWindow.webContents.send("user:error", error); + ipcMain.once("user:error:reply", (e, reply) => { + switch (reply) { + case "ignore": + utils.log.warn("error ignored"); + if (ignore) setTimeout(ignore, 500); + break; + case "restart": + utils.log.warn("restart after error"); + if (restart) setTimeout(restart, 500); + else mainEvent.emit("restart"); + break; + case "bugreport": + utils.sendBugReport(error); + break; + default: + break; + } + }); + } else { + process.exit(1); + } } catch (e) { process.exit(1); } }); // Connection to the device was lost -mainEvent.on("user:connection-lost", callback => { - if (mainWindow) - mainWindow.webContents.send( - "user:connection-lost", - callback || mainWindow.reload() - ); +mainEvent.on("user:connection-lost", reconnect => { + if (mainWindow) mainWindow.webContents.send("user:connection-lost"); + ipcMain.once("reconnect", () => { + if (reconnect) setTimeout(reconnect, 500); + else mainEvent.emit("restart"); + }); }); // The device battery is too low to install @@ -218,7 +237,8 @@ mainEvent.on("user:low-power", () => { // Restart the installer mainEvent.on("restart", () => { - global.installProperties.device = undefined; + global.installProperties = { settings: {} }; + global.installConfig = {}; utils.log.debug("WINDOW RELOADED"); mainWindow.reload(); }); @@ -317,27 +337,23 @@ mainEvent.on("user:configure", osInstructs => { mainEvent.on("device", device => { global.installProperties.device = device; function continueWithConfig() { - if (global.installConfig.operating_systems.length > 1) { - // ask for os selection if there's one os - mainWindow.webContents.send( - "user:os", - global.installConfig, - devices.getOsSelects(global.installConfig.operating_systems) - ); - } else { - // immediately jump to configure if there's only one os - global.installProperties.osIndex = 0; - mainEvent.emit( - "user:configure", - global.installConfig.operating_systems[0] - ); - } + mainWindow.webContents.send( + "user:os", + global.installConfig, + devices.getOsSelects(global.installConfig.operating_systems) + ); } if (global.installConfig && global.installConfig.operating_systems) { // local config specified continueWithConfig(); } else { - // local config specified + // fetch remote config + global.mainEvent.emit("user:write:working", "particles"); + global.mainEvent.emit("user:write:status", "Preparing installation", true); + global.mainEvent.emit( + "user:write:under", + "Fetching installation instructions" + ); api .getDevice(device) .then(config => { diff --git a/src/utils.js b/src/utils.js index cd2dc5bc..ce1222b6 100644 --- a/src/utils.js +++ b/src/utils.js @@ -391,13 +391,13 @@ function downloadFiles(urls, progress, next) { }); } -function errorToUser(error, errorLocation) { +function errorToUser(error, errorLocation, restart, ignore) { var errorString = "Error: " + (errorLocation ? errorLocation : "Unknown") + ": " + error; utils.log.error( errorString + (error.stack ? "\nstack trace: " + error.stack : "") ); - global.mainEvent.emit("user:error", errorString); + global.mainEvent.emit("user:error", errorString, restart, ignore); } module.exports = {