+ Home Assistant instance is not available, please check your + connection. +
+diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dee06a3..b7174f5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,7 @@ name: Build/release on: push: tags: - - '*' + - "*" jobs: release: @@ -30,6 +30,8 @@ jobs: # (No need to define this secret in the repo settings) github_token: ${{ secrets.github_token }} + args: "--ia32" + mac_certs: ${{ secrets.mac_certs }} mac_certs_password: ${{ secrets.mac_certs_password }} diff --git a/.gitignore b/.gitignore index 82ee25a..ef08393 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules dist .idea +.DS_Store diff --git a/LICENSE.md b/LICENSE.md index 261eeb9..24a945b 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -2,180 +2,180 @@ Version 2.0, January 2004 http://www.apache.org/licenses/ - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - 1. Definitions. +1. Definitions. - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. - END OF TERMS AND CONDITIONS +END OF TERMS AND CONDITIONS - APPENDIX: How to apply the Apache License to your work. +APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" @@ -186,16 +186,16 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] +Copyright [yyyy][name of copyright owner] - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/README.md b/README.md index aeaa224..3451874 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,26 @@ # Home Assistant - Desktop -Desktop App (Windows / macOS) for [Home Assistant](https://www.home-assistant.io/) built with [Electron](https://www.electronjs.org/) - -## Installation -Just download the latest version for your platform from the [Releases Section](https://github.com/mrvnklm/homeassistant-desktop/releases) to install Home Assistant +Desktop App (Windows / macOS) for [Home Assistant](https://www.home-assistant.io/) built with [Electron](https://www.electronjs.org) -## Usage -- Click the tray icon to open Home Assistant -- Right-Click to open context menu and change some settings / reset / quit the app -- Updates are installed automatically if a new version is available (restart required) + + +## Installation + +Just download the latest version for your platform from the [releases section](https://github.com/mrvnklm/homeassistant-desktop/releases) to install Home Assistant + +## Usage / Features + +- hover / click the tray icon to open the app +- supports multiple instances of Home Assistant (including automatic switching) +- right-click to open context menu and change some settings / reset / quit the app +- updates are installed automatically if a new version is available (restart required) ## License + Home Assistant Desktop is open-source and [Apache 2](https://choosealicense.com/licenses/apache-2.0/) licensed ## Contributing + Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. I like coffee, so if you feel like buying one for me - go ahead! diff --git a/app.js b/app.js index 164bc4b..143ea66 100644 --- a/app.js +++ b/app.js @@ -1,348 +1,486 @@ -const {app, Menu, Tray, dialog, ipcMain, BrowserWindow, shell, screen} = require('electron'); -const {autoUpdater} = require('electron-updater'); -const AutoLaunch = require('auto-launch'); -const Positioner = require('electron-traywindow-positioner'); -const Store = require('electron-store'); +const { + app, + dialog, + ipcMain, + shell, + screen, + net, + Menu, + Tray, + BrowserWindow, +} = require("electron"); +const { autoUpdater } = require("electron-updater"); +const AutoLaunch = require("auto-launch"); +const Positioner = require("electron-traywindow-positioner"); +const Store = require("electron-store"); app.allowRendererProcessReuse = true; // prevent multiple instances if (!app.requestSingleInstanceLock()) { - app.quit() + app.quit(); } else { - app.on('second-instance', () => { - if (window) showWindow(); - }) + app.on("second-instance", () => { + if (window) showWindow(); + }); } // hide dock icon on macOS -if (process.platform === 'darwin') app.dock.hide(); +if (process.platform === "darwin") app.dock.hide(); const store = new Store(); -const autoLauncher = new AutoLaunch({name: 'Home Assistant Desktop'}); +const autoLauncher = new AutoLaunch({ name: "Home Assistant Desktop" }); const indexFile = `file://${__dirname}/web/index.html`; +const errorFile = `file://${__dirname}/web/error.html`; + let autostartEnabled = false; let forceQuit = false; - +let resizeEvent = false; const useAutoUpdater = () => { - autoUpdater.on('error', message => { - console.error('There was a problem updating the application'); - console.error(message) - }); + autoUpdater.on("error", (message) => { + console.error("There was a problem updating the application"); + console.error(message); + }); - autoUpdater.on('update-downloaded', () => { - forceQuit = true; - autoUpdater.quitAndInstall(); - }); - - setInterval(() => { - autoUpdater.checkForUpdates(); - }, 1000 * 60 * 30); + autoUpdater.on("update-downloaded", () => { + forceQuit = true; + autoUpdater.quitAndInstall(); + }); + setInterval(() => { autoUpdater.checkForUpdates(); + }, 1000 * 60 * 60); + + autoUpdater.checkForUpdates(); }; const checkAutoStart = () => { - autoLauncher.isEnabled().then((isEnabled) => { - autostartEnabled = isEnabled; - }).catch((err) => { - console.error(err) + autoLauncher + .isEnabled() + .then((isEnabled) => { + autostartEnabled = isEnabled; + }) + .catch((err) => { + console.error(err); }); }; +const startAvailabilityCheck = () => { + setInterval(() => { + const request = net.request(`${currentInstance()}/auth/providers`); + request.on("response", (response) => { + showError(response.statusCode !== 200); + }); + request.on("error", (error) => { + showError(true); + if (store.get("automaticSwitching")) checkForAvailableInstance(); + }); + request.end(); + }, 3000); +}; + +const checkForAvailableInstance = () => { + const instances = store.get("allInstances"); + + if (instances && instances.length > 1) { + instances + .filter((e) => e.url !== currentInstance()) + .forEach((e) => { + const request = net.request(`${e}/auth/providers`); + request.on("response", (response) => { + if (response.statusCode === 200) currentInstance(e); + }); + request.on("error", (error) => {}); + request.end(); + }); + } +}; + const getMenu = () => { - let instancesMenu = [{ - label: 'Open in Browser', - enabled: currentInstance(), - click: () => { - shell.openExternal(currentInstance()) - } + let instancesMenu = [ + { + label: "Open in Browser", + enabled: currentInstance(), + click: () => { + shell.openExternal(currentInstance()); + }, }, - { - type: 'separator' - } - ]; + { + type: "separator", + }, + ]; - const allInstances = store.get('allInstances'); + const allInstances = store.get("allInstances"); - if (allInstances) { - allInstances.forEach((e) => { - instancesMenu.push({ - label: e, - type: 'checkbox', - checked: currentInstance() === e, - click: () => { - currentInstance(e); - window.loadURL(e); - window.show(); - } - }); - }); + if (allInstances) { + allInstances.forEach((e) => { + instancesMenu.push({ + label: e, + type: "checkbox", + checked: currentInstance() === e, + click: () => { + currentInstance(e); + window.loadURL(e); + window.show(); + }, + }); + }); - instancesMenu.push( - { - type: 'separator' - }, - { - label: 'Add another Instance...', click: () => { - store.delete('currentInstance'); - window.loadURL(indexFile); - window.show(); - } - } - ) - } else { - instancesMenu.push({label: 'Not Connected...', enabled: false}) - } + instancesMenu.push( + { + type: "separator", + }, + { + label: "Add another Instance...", + click: () => { + store.delete("currentInstance"); + window.loadURL(indexFile); + window.show(); + }, + }, + { + label: "Automatic Switching", + type: "checkbox", + enabled: + store.has("allInstances") && store.get("allInstances").length > 1, + checked: store.get("automaticSwitching"), + click: () => { + store.set("automaticSwitching", store.get("automaticSwitching")); + }, + } + ); + } else { + instancesMenu.push({ label: "Not Connected...", enabled: false }); + } - return Menu.buildFromTemplate([...instancesMenu, - { - type: 'separator' - }, - { - label: 'Hover to Show', - enabled: !store.get('detachedMode'), - type: 'checkbox', - checked: !store.get('disableHover'), - click: () => { - store.set('disableHover', !store.get('disableHover')) + return Menu.buildFromTemplate([ + ...instancesMenu, + { + type: "separator", + }, + { + label: "Hover to Show", + enabled: !store.get("detachedMode"), + type: "checkbox", + checked: !store.get("disableHover"), + click: () => { + store.set("disableHover", !store.get("disableHover")); + }, + }, + { + label: "Stay on Top", + type: "checkbox", + checked: window.isAlwaysOnTop(), + click: () => { + window.setAlwaysOnTop(!window.isAlwaysOnTop()); + if (window.isAlwaysOnTop()) showWindow(); + }, + }, + { + label: "Start at Login", + type: "checkbox", + checked: autostartEnabled, + click: () => { + if (autostartEnabled) autoLauncher.disable(); + else autoLauncher.enable(); + checkAutoStart(); + }, + }, + { + type: "separator", + }, + { + label: "Use detached Window", + type: "checkbox", + checked: store.get("detachedMode"), + click: () => { + store.set("detachedMode", !store.get("detachedMode")); + window.hide(); + createMainWindow(store.get("detachedMode")); + }, + }, + { + type: "separator", + }, + { + label: `v${app.getVersion()} (Auto Update)`, + enabled: false, + }, + { + label: "Open on github.com", + click: () => { + shell.openExternal("https://github.com/mrvnklm/homeassistant-desktop"); + }, + }, + { + type: "separator", + }, + { + label: "Reload Window", + click: () => { + window.reload(); + }, + }, + { + label: "Reset Application...", + click: () => { + dialog + .showMessageBox({ + message: "Are you sure you want to reset Home Assistant Desktop?", + buttons: ["Reset Everything!", "Reset Windows", "Cancel"], + }) + .then((res) => { + if (res.response === 0) { + store.clear(); + window.webContents.session.clearCache(); + window.webContents.session.clearStorageData(); + app.relaunch(); + app.exit(); } - }, - { - label: 'Stay on Top', - type: 'checkbox', - checked: window.isAlwaysOnTop(), - click: () => { - window.setAlwaysOnTop(!window.isAlwaysOnTop()); - if (window.isAlwaysOnTop()) showWindow(); + if (res.response === 1) { + store.delete("windowSizeDetached"); + store.delete("windowSize"); + store.delete("windowPosition"); + app.relaunch(); + app.exit(); } - }, - { - label: 'Start at Login', - type: 'checkbox', - checked: autostartEnabled, - click: () => { - if (autostartEnabled) autoLauncher.disable(); else autoLauncher.enable(); - checkAutoStart() - } - }, { - type: 'separator' - }, - { - label: 'Use detached Window', - type: 'checkbox', - checked: store.get('detachedMode'), - click: () => { - store.set('detachedMode', !store.get('detachedMode')); - window.hide(); - createMainWindow(store.get('detachedMode')) - } - }, - { - type: 'separator' - }, - { - label: `v${app.getVersion()} (Auto Update)`, - enabled: false - }, - { - label: 'Open on github.com', - click: () => { - shell.openExternal('https://github.com/mrvnklm/homeassistant-desktop') - } - }, - { - type: 'separator' - }, - { - label: 'Reload Window', - click: () => { - window.reload(); - } - }, - { - label: 'Reset Settings...', - click: () => { - dialog.showMessageBox({ - message: 'Are you sure you want to reset Home Assistant Desktop?', - buttons: ['Cancel', 'OK, Reset!'] - }).then((res) => { - if (res.response === 1) { - store.clear(); - window.webContents.session.clearCache(); - window.webContents.session.clearStorageData(); - app.relaunch(); - app.exit(); - } - }) - } - }, - { - type: 'separator' - }, - { - label: 'Quit', - accelerator: 'Cmd+Q', - click: () => { - forceQuit = true; - app.quit(); - } - } - ]) + }); + }, + }, + { + type: "separator", + }, + { + label: "Quit", + click: () => { + forceQuit = true; + app.quit(); + }, + }, + ]); }; const createMainWindow = (show = false) => { - window = new BrowserWindow({ - width: 420, - height: 420, - show: false, - skipTaskbar: true, - autoHideMenuBar: true, - frame: false, - webPreferences: { - nodeIntegration: true + window = new BrowserWindow({ + width: 420, + height: 420, + show: false, + skipTaskbar: true, + autoHideMenuBar: true, + frame: false, + webPreferences: { + nodeIntegration: true, + }, + }); + + // window.webContents.openDevTools(); + window.loadURL(indexFile); + + // open extenal links in default browser + window.webContents.on("new-window", function (e, url) { + e.preventDefault(); + require("electron").shell.openExternal(url); + }); + + // hide scrollbar + window.webContents.on("did-finish-load", function () { + window.webContents.insertCSS( + "::-webkit-scrollbar { display: none; } body { -webkit-user-select: none; }" + ); + if (store.get("detachedMode")) { + window.webContents.insertCSS("body { -webkit-app-region: drag; }"); + } + }); + + if (store.get("detachedMode")) { + if (store.has("windowPosition")) + window.setSize(...store.get("windowSizeDetached")); + else store.set("windowPosition", window.getPosition()); + if (store.has("windowSizeDetached")) + window.setPosition(...store.get("windowPosition")); + else store.set("windowSizeDetached", window.getSize()); + } else { + if (store.has("windowSize")) window.setSize(...store.get("windowSize")); + else store.set("windowSize", window.getSize()); + } + + window.on("resize", (e) => { + if (!store.get("disableHover") || resizeEvent) { + store.set("disableHover", true); + resizeEvent = e; + setTimeout(() => { + if (resizeEvent === e) { + store.set("disableHover", false); + resizeEvent = false; } - }); - - window.loadURL(indexFile); - - window.webContents.on('did-finish-load', function () { - window.webContents.insertCSS('::-webkit-scrollbar { display: none; } body { -webkit-user-select: none; }'); - if (store.get('detachedMode')) { - window.webContents.insertCSS('body { -webkit-app-region: drag; }'); - } - }); - - if (store.get('detachedMode')) { - if (store.has('windowPosition')) window.setSize(...store.get('windowSizeDetached')); else store.set('windowPosition', window.getPosition()); - if (store.has('windowSizeDetached')) window.setPosition(...store.get('windowPosition')); else store.set('windowSizeDetached', window.getSize()) - } else { - if (store.has('windowSize')) window.setSize(...store.get('windowSize')); else store.set('windowSize', window.getSize()) + }, 600); } - window.on('resize', () => { - if (store.get('detachedMode')) { - store.set('windowSizeDetached', window.getSize()); - } else { - Positioner.position(window, tray.getBounds()); - store.set('windowSize', window.getSize()); - } + if (store.get("detachedMode")) { + store.set("windowSizeDetached", window.getSize()); + } else { + Positioner.position(window, tray.getBounds()); + store.set("windowSize", window.getSize()); + } + }); - }); + window.on("move", () => { + if (store.get("detachedMode")) { + store.set("windowPosition", window.getPosition()); + } + }); - window.on('move', () => { - if (store.get('detachedMode')) { - store.set('windowPosition', window.getPosition()) - } - }); + window.on("close", (e) => { + if (!forceQuit) { + window.hide(); + e.preventDefault(); + } + }); - window.on('close', (e) => { - if (!forceQuit) { - window.hide(); - e.preventDefault() - } - }); + window.on("blur", () => { + if (!store.get("detachedMode") && !window.isAlwaysOnTop()) window.hide(); + }); - window.on('blur', () => { - if (!store.get('detachedMode') && !window.isAlwaysOnTop()) window.hide(); - }); - - if (show) showWindow(); + if (show) showWindow(); }; const showWindow = () => { - if (!store.get('detachedMode')) Positioner.position(window, tray.getBounds()); - if (!window.isVisible()) { - window.show(); - window.focus(); - } + if (!store.get("detachedMode")) Positioner.position(window, tray.getBounds()); + if (!window.isVisible()) { + window.setVisibleOnAllWorkspaces(true); // put the window on all screens + window.show(); + window.focus(); + window.setVisibleOnAllWorkspaces(false); // disable all screen behavior + } }; const createTray = () => { - tray = new Tray(process.platform === 'win32' ? `${__dirname}/assets/IconWin.png` : `${__dirname}/assets/IconTemplate.png`); + tray = new Tray( + process.platform === "win32" + ? `${__dirname}/assets/IconWin.png` + : `${__dirname}/assets/IconTemplate.png` + ); - tray.on('click', () => { - if (window.isVisible()) window.hide(); else showWindow(); - }); + tray.on("click", () => { + if (window.isVisible()) window.hide(); + else showWindow(); + }); - tray.on('right-click', () => { - if (!store.get('detachedMode')) window.hide(); - tray.popUpContextMenu(getMenu()) - }); + tray.on("right-click", () => { + if (!store.get("detachedMode")) window.hide(); + tray.popUpContextMenu(getMenu()); + }); - let timer = undefined; + let timer = undefined; - tray.on('mouse-move', (e) => { - if (store.get('detachedMode') || window.isAlwaysOnTop() || store.get('disableHover')) { - return; - } - if (!window.isVisible()) { - showWindow(); - } - if (timer) clearTimeout(timer); - timer = setTimeout(() => { - let mousePos = screen.getCursorScreenPoint(); - let trayBounds = tray.getBounds(); - if (!(mousePos.x >= trayBounds.x && mousePos.x <= trayBounds.x + trayBounds.width) || !(mousePos.y >= trayBounds.y && mousePos.y <= trayBounds.y + trayBounds.height)) { - setWindowFocusTimer() - } - }, 100); - } - ) + tray.on("mouse-move", (e) => { + if ( + store.get("detachedMode") || + window.isAlwaysOnTop() || + store.get("disableHover") + ) { + return; + } + if (!window.isVisible()) { + showWindow(); } -; -const setWindowFocusTimer = () => { - let timer = setTimeout(() => { - let mousePos = screen.getCursorScreenPoint(); - let windowPosition = window.getPosition(); - let windowSize = window.getSize(); - if (!(mousePos.x >= windowPosition[0] && mousePos.x <= windowPosition[0] + windowSize[0]) || !(mousePos.y >= windowPosition[1] && mousePos.y <= windowPosition[1] + windowSize[1])) { - window.hide(); - } else { - setWindowFocusTimer() - } - }, 110) + if (timer) clearTimeout(timer); + timer = setTimeout(() => { + let mousePos = screen.getCursorScreenPoint(); + let trayBounds = tray.getBounds(); + if ( + !( + mousePos.x >= trayBounds.x && + mousePos.x <= trayBounds.x + trayBounds.width + ) || + !( + mousePos.y >= trayBounds.y && + mousePos.y <= trayBounds.y + trayBounds.height + ) + ) { + setWindowFocusTimer(); + } + }, 100); + }); }; -app.on('ready', () => { - // temporary migration of instances to avoid breaking active instance - if (store.has('instance')) { - store.set('allInstances', [store.get('instance').url]); - store.set('currentInstance', 0); - store.delete('instance'); +const setWindowFocusTimer = () => { + let timer = setTimeout(() => { + let mousePos = screen.getCursorScreenPoint(); + let windowPosition = window.getPosition(); + let windowSize = window.getSize(); + if ( + !resizeEvent && + (!( + mousePos.x >= windowPosition[0] && + mousePos.x <= windowPosition[0] + windowSize[0] + ) || + !( + mousePos.y >= windowPosition[1] && + mousePos.y <= windowPosition[1] + windowSize[1] + )) + ) { + window.hide(); + } else { + setWindowFocusTimer(); } - checkAutoStart(); - useAutoUpdater(); - createTray(); - createMainWindow(!store.has('currentInstance')); + }, 110); +}; + +app.on("ready", () => { + checkAutoStart(); + useAutoUpdater(); + createTray(); + createMainWindow(!store.has("currentInstance")); + startAvailabilityCheck(); + + // disable hover for first start + if (!store.has("currentInstance")) { + store.set("disableHover", true); + } }); const currentInstance = (url = null) => { - if (url) { - store.set('currentInstance', store.get('allInstances').indexOf(url)); - } - if (store.has('currentInstance')) { - return store.get('allInstances')[store.get('currentInstance')]; - } - return false; + if (url) { + store.set("currentInstance", store.get("allInstances").indexOf(url)); + } + if (store.has("currentInstance")) { + return store.get("allInstances")[store.get("currentInstance")]; + } + return false; }; const addInstance = (url) => { - if (!store.has('allInstances')) store.set('allInstances', []); - let instances = store.get('allInstances'); - if (instances.find(e => e === url)) { - return; - } - instances.push(url); - store.set('allInstances', instances); - currentInstance(url) + if (!store.has("allInstances")) store.set("allInstances", []); + let instances = store.get("allInstances"); + if (instances.find((e) => e === url)) { + currentInstance(url); + return; + } + + // active hover by default after adding first instance + if (!instances.length) store.set("disableHover", false); + + instances.push(url); + store.set("allInstances", instances); + currentInstance(url); }; -ipcMain.on('ha-instance', (event, args) => { - if (args) addInstance(args.url); - console.log(currentInstance()); - if (currentInstance()) event.reply('ha-instance', currentInstance()) +const showError = (isError) => { + if (!isError && window.webContents.getURL().includes("error.html")) + window.loadURL(indexFile); + if ( + isError && + currentInstance() && + !window.webContents.getURL().includes("error.html") + ) + window.loadURL(errorFile); +}; + +ipcMain.on("ha-instance", (event, url) => { + if (url) addInstance(url); + if (currentInstance()) event.reply("ha-instance", currentInstance()); }); diff --git a/package-lock.json b/package-lock.json index 6e7f2b8..91925cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homeassistant-desktop", - "version": "1.0.0", + "version": "1.2.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -93,23 +93,23 @@ "dev": true }, "@types/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-UoOfVEzAUpeSPmjm7h1uk5MH6KZma2z2O7a75onTGjnNvAvMVrPzPL/vBbT65iIGHWj6rokwfmYcmxmlSf2uwg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-B42Sxuaz09MhC3DDeW5kubRcQ5by4iuVQ0cRRWM2lggLzAa/KVom0Aft/208NgMvNQQZ86s5rVcqDdn/SH0/mg==", "dev": true, "requires": { "@types/node": "*" } }, "@types/node": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.1.tgz", - "integrity": "sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA==" + "version": "14.0.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.27.tgz", + "integrity": "sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g==" }, "@types/semver": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.2.0.tgz", - "integrity": "sha512-TbB0A8ACUWZt3Y6bQPstW9QNbhNeebdgLX4T/ZfkrswAfUzRiXrgd9seol+X379Wa589Pu4UEx9Uok0D4RjRCQ==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.1.tgz", + "integrity": "sha512-ooD/FJ8EuwlDKOI6D9HWxgIgJjMg2cuziXm/42npDC8y4NjxplBUn9loewZiBNCt44450lHAU0OSb51/UqXeag==", "requires": { "@types/node": "*" } @@ -130,9 +130,9 @@ "dev": true }, "ajv": { - "version": "6.12.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", - "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -141,9 +141,9 @@ } }, "ajv-keywords": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", - "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true }, "ansi-align": { @@ -185,32 +185,32 @@ } }, "app-builder-bin": { - "version": "3.5.8", - "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.5.8.tgz", - "integrity": "sha512-ni3q7QTfQNWHNWuyn5x3FZu6GnQZv+TFnfgk5++svqleKEhHGqS1mIaKsh7x5pBX6NFXU3/+ktk98wA/AW4EXw==", + "version": "3.5.9", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.5.9.tgz", + "integrity": "sha512-NSjtqZ3x2kYiDp3Qezsgukx/AUzKPr3Xgf9by4cYt05ILWGAptepeeu0Uv+7MO+41o6ujhLixTou8979JGg2Kg==", "dev": true }, "app-builder-lib": { - "version": "22.6.0", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.6.0.tgz", - "integrity": "sha512-ky2aLYy92U+Gh6dKq/e8/bNmCotp6/GMhnX8tDZPv9detLg9WuBnWWi1ktBPlpbl1DREusy+TIh+9rgvfduQoA==", + "version": "22.8.0", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.8.0.tgz", + "integrity": "sha512-RGaIRjCUrqkmh6QOGsyekQPEOaVynHfmeh8JZuyUymFYUOFdzBbPamkA2nhBVBTkkgfjRHsxK7LhedFKPzvWEQ==", "dev": true, "requires": { "7zip-bin": "~5.0.3", "@develar/schema-utils": "~2.6.5", "async-exit-hook": "^2.0.1", "bluebird-lst": "^1.0.9", - "builder-util": "22.6.0", - "builder-util-runtime": "8.7.0", + "builder-util": "22.8.0", + "builder-util-runtime": "8.7.2", "chromium-pickle-js": "^0.2.0", "debug": "^4.1.1", - "ejs": "^3.1.2", - "electron-publish": "22.6.0", - "fs-extra": "^9.0.0", - "hosted-git-info": "^3.0.4", + "ejs": "^3.1.3", + "electron-publish": "22.8.0", + "fs-extra": "^9.0.1", + "hosted-git-info": "^3.0.5", "is-ci": "^2.0.0", "isbinaryfile": "^4.0.6", - "js-yaml": "^3.13.1", + "js-yaml": "^3.14.0", "lazy-val": "^1.0.4", "minimatch": "^3.0.4", "normalize-package-data": "^2.5.0", @@ -355,31 +355,31 @@ "dev": true }, "builder-util": { - "version": "22.6.0", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.6.0.tgz", - "integrity": "sha512-jgdES2ExJYkuXC3DEaGAjFctKNA81C4QDy8zdoc+rqdSqheTizuDNtZg02uMFklmUES4V4fggmqds+Y7wraqng==", + "version": "22.8.0", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.8.0.tgz", + "integrity": "sha512-H80P1JzVy3TGpi63x81epQDK24XalL034+jAZlrPb5IhLtYmnNNdxCCAVJvg3VjSISd73Y71O+uhqCxWpqbPHw==", "dev": true, "requires": { "7zip-bin": "~5.0.3", "@types/debug": "^4.1.5", - "@types/fs-extra": "^8.1.0", - "app-builder-bin": "3.5.8", + "@types/fs-extra": "^9.0.1", + "app-builder-bin": "3.5.9", "bluebird-lst": "^1.0.9", - "builder-util-runtime": "8.7.0", - "chalk": "^4.0.0", + "builder-util-runtime": "8.7.2", + "chalk": "^4.1.0", "debug": "^4.1.1", - "fs-extra": "^9.0.0", + "fs-extra": "^9.0.1", "is-ci": "^2.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^3.14.0", "source-map-support": "^0.5.19", "stat-mode": "^1.0.0", "temp-file": "^3.3.7" } }, "builder-util-runtime": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.0.tgz", - "integrity": "sha512-G1AqqVM2vYTrSFR982c1NNzwXKrGLQjVjaZaWQdn4O6Z3YKjdMDofw88aD9jpyK9ZXkrCxR0tI3Qe9wNbyTlXg==", + "version": "8.7.2", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.2.tgz", + "integrity": "sha512-xBqv+8bg6cfnzAQK1k3OGpfaHg+QkPgIgpEkXNhouZ0WiUkyZCftuRc2LYzQrLucFywpa14Xbc6+hTbpq83yRA==", "requires": { "debug": "^4.1.1", "sax": "^1.2.4" @@ -401,9 +401,9 @@ }, "dependencies": { "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, "requires": { "pump": "^3.0.0" @@ -424,9 +424,9 @@ "dev": true }, "chalk": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", - "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -643,16 +643,16 @@ "optional": true }, "dmg-builder": { - "version": "22.6.0", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.6.0.tgz", - "integrity": "sha512-rJxuGhHIpcuDGBtWZMM8aLxkbZNgYO2MO5dUerDIBXebhX1K8DA23iz/uZ8ahcRNgWEv57b8GDqJbXKEfr5T0A==", + "version": "22.8.0", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.8.0.tgz", + "integrity": "sha512-orePWjcrl97SYLA8F/6UUtbXJSoZCYu5KOP1lVqD4LOomr8bjGDyEVYZmZYcg5WqKmXucdmO6OpqgzH/aRMMuA==", "dev": true, "requires": { - "app-builder-lib": "22.6.0", - "builder-util": "22.6.0", - "fs-extra": "^9.0.0", - "iconv-lite": "^0.5.1", - "js-yaml": "^3.13.1", + "app-builder-lib": "22.8.0", + "builder-util": "22.8.0", + "fs-extra": "^9.0.1", + "iconv-lite": "^0.6.2", + "js-yaml": "^3.14.0", "sanitize-filename": "^1.6.3" } }, @@ -683,18 +683,18 @@ "dev": true }, "ejs": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.2.tgz", - "integrity": "sha512-zFuywxrAWtX5Mk2KAuoJNkXXbfezpNA0v7i+YC971QORguPekpjpAgeOv99YWSdKXwj7JxI2QAWDeDkE8fWtXw==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.3.tgz", + "integrity": "sha512-wmtrUGyfSC23GC/B1SMv2ogAUgbQEtDmTIhfqielrG5ExIM9TP4UoYdi90jLF1aTcsWCJNEO0UrgKzP0y3nTSg==", "dev": true, "requires": { "jake": "^10.6.1" } }, "electron": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-8.3.0.tgz", - "integrity": "sha512-XRjiIJICZCgUr2vKSUI2PTkfP0gPFqCtqJUaTJSfCTuE3nTrxBKOUNeRMuCzEqspKkpFQU3SB3MdbMSHmZARlQ==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-8.5.0.tgz", + "integrity": "sha512-ERqSTRlaQ4PqME5a1z9DWQbwQy2LbgSN1Jnau1MJCRRvHgq1FJlqbbb/ij/RGWuQuaxy4Djb2KnTs5rsemR5mQ==", "dev": true, "requires": { "@electron/get": "^1.0.1", @@ -703,27 +703,27 @@ }, "dependencies": { "@types/node": { - "version": "12.12.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.39.tgz", - "integrity": "sha512-pADGfwnDkr6zagDwEiCVE4yQrv7XDkoeVa4OfA9Ju/zRTk6YNDLGtQbkdL4/56mCQQCs4AhNrBIag6jrp7ZuOg==", + "version": "12.12.54", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.54.tgz", + "integrity": "sha512-ge4xZ3vSBornVYlDnk7yZ0gK6ChHf/CHB7Gl1I0Jhah8DDnEQqBzgohYG4FX4p81TNirSETOiSyn+y1r9/IR6w==", "dev": true } } }, "electron-builder": { - "version": "22.6.0", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.6.0.tgz", - "integrity": "sha512-aLHlB6DTfjJ3MI4AUIFeWnwIozNgNlbOk2c2sTHxB10cAKp0dBVSPZ7xF5NK0uwDhElvRzJQubnHtJD6zKg42Q==", + "version": "22.8.0", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.8.0.tgz", + "integrity": "sha512-dUv4F3srJouqxhWivtKqSoQP4Df6vYgjooGdzms+iYMTFi9f0b4LlEbr7kgsPvte8zAglee7VOGOODkCRJDkUQ==", "dev": true, "requires": { - "@types/yargs": "^15.0.4", - "app-builder-lib": "22.6.0", + "@types/yargs": "^15.0.5", + "app-builder-lib": "22.8.0", "bluebird-lst": "^1.0.9", - "builder-util": "22.6.0", - "builder-util-runtime": "8.7.0", - "chalk": "^4.0.0", - "dmg-builder": "22.6.0", - "fs-extra": "^9.0.0", + "builder-util": "22.8.0", + "builder-util-runtime": "8.7.2", + "chalk": "^4.1.0", + "dmg-builder": "22.8.0", + "fs-extra": "^9.0.1", "is-ci": "^2.0.0", "lazy-val": "^1.0.4", "read-config-file": "6.0.0", @@ -733,25 +733,25 @@ } }, "electron-publish": { - "version": "22.6.0", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.6.0.tgz", - "integrity": "sha512-+v05SBf9qR7Os5au+fifloNHy5QxHQkUGudBj68YaTb43Pn37UkwRxSc49Lf13s4wW32ohM45g8BOVInPJEdnA==", + "version": "22.8.0", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.8.0.tgz", + "integrity": "sha512-uM0Zdi9hUqqGOrPj478v7toTvV1Kgto1w11rIiI168batiXAJvNLD8VZRfehOrZT0ibUyZlw8FtxoGCrjyHUOw==", "dev": true, "requires": { - "@types/fs-extra": "^8.1.0", + "@types/fs-extra": "^9.0.1", "bluebird-lst": "^1.0.9", - "builder-util": "22.6.0", - "builder-util-runtime": "8.7.0", - "chalk": "^4.0.0", - "fs-extra": "^9.0.0", + "builder-util": "22.8.0", + "builder-util-runtime": "8.7.2", + "chalk": "^4.1.0", + "fs-extra": "^9.0.1", "lazy-val": "^1.0.4", - "mime": "^2.4.4" + "mime": "^2.4.6" } }, "electron-store": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/electron-store/-/electron-store-5.1.1.tgz", - "integrity": "sha512-FLidOVE8JVCdJXHd7xY/JojKJ2r2WNmWt0O/LlX2LuSVV7dkG2RSy2/Gm2LFw8OKDfrNBd9c/s4X1ikMrJEUKg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/electron-store/-/electron-store-5.2.0.tgz", + "integrity": "sha512-iU3WDqEDAYNYR9XV7p0tJajq/zs9z7Nrn0sAoR5nDyn8h/9dr9kusKbTxD8NtVEBD1TB1pkGMqcbIt/y6knDwQ==", "requires": { "conf": "^6.2.1", "type-fest": "^0.7.1" @@ -763,17 +763,17 @@ "integrity": "sha512-/i1jh1L8qyUJAZ1KVT67SEK/OZ+3F2Qfe8mCfuXHSVC5tAOuw3U971LuxMvAsJJS/yNW0oSQ9pCbVzqGlNCeJQ==" }, "electron-updater": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-4.3.1.tgz", - "integrity": "sha512-UDC5AHCgeiHJYDYWZG/rsl1vdAFKqI/Lm7whN57LKAk8EfhTewhcEHzheRcncLgikMcQL8gFo1KeX51tf5a5Wg==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-4.3.4.tgz", + "integrity": "sha512-ekpgxDrYl+Wi24ktO4qfj2CtCABxrmK1C/oekp0tai6q4VR4ZdPkit4CX8+GenvKMme7uMmfPFnLp/vwhP/ThQ==", "requires": { - "@types/semver": "^7.1.0", - "builder-util-runtime": "8.7.0", - "fs-extra": "^9.0.0", - "js-yaml": "^3.13.1", + "@types/semver": "^7.3.1", + "builder-util-runtime": "8.7.2", + "fs-extra": "^9.0.1", + "js-yaml": "^3.14.0", "lazy-val": "^1.0.4", "lodash.isequal": "^4.5.0", - "semver": "^7.1.3" + "semver": "^7.3.2" }, "dependencies": { "semver": { @@ -824,9 +824,9 @@ "dev": true }, "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "optional": true }, @@ -865,9 +865,9 @@ } }, "fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-json-stable-stringify": { "version": "2.1.0", @@ -901,9 +901,9 @@ } }, "fs-extra": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz", - "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", "requires": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -927,19 +927,19 @@ } }, "global-agent": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.8.tgz", - "integrity": "sha512-VpBe/rhY6Rw2VDOTszAMNambg+4Qv8j0yiTNDYEXXXxkUNGWLHp8A3ztK4YDBbFNcWF4rgsec6/5gPyryya/+A==", + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.12.tgz", + "integrity": "sha512-caAljRMS/qcDo69X9BfkgrihGUgGx44Fb4QQToNQjsiWh+YlQ66uqYVAdA8Olqit+5Ng0nkz09je3ZzANMZcjg==", "dev": true, "optional": true, "requires": { - "boolean": "^3.0.0", - "core-js": "^3.6.4", + "boolean": "^3.0.1", + "core-js": "^3.6.5", "es6-error": "^4.1.1", - "matcher": "^2.1.0", - "roarr": "^2.15.2", - "semver": "^7.1.2", - "serialize-error": "^5.0.0" + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" }, "dependencies": { "semver": { @@ -1020,12 +1020,12 @@ "dev": true }, "hosted-git-info": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.4.tgz", - "integrity": "sha512-4oT62d2jwSDBbLLFLZE+1vPuQ1h8p9wjrJ8Mqx5TjsyWmBMV5B13eJqn8pvluqubLf3cJPTfiYCIwNwDNmzScQ==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.5.tgz", + "integrity": "sha512-i4dpK6xj9BIpVOTboXIlKG9+8HMKggcrMX7WA24xZtKwX0TPelq/rbaS5rCKeNX8sJXZJGdSxpnEGtta+wismQ==", "dev": true, "requires": { - "lru-cache": "^5.1.1" + "lru-cache": "^6.0.0" } }, "http-cache-semantics": { @@ -1035,12 +1035,12 @@ "dev": true }, "iconv-lite": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.1.tgz", - "integrity": "sha512-ONHr16SQvKZNSqjQT9gy5z24Jw+uqfO02/ngBSBoqChZ+W8qXX7GPRa1RoUnzGADw8K63R1BXUMzarCVQBpY8Q==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", "dev": true, "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "import-lazy": { @@ -1132,9 +1132,9 @@ "dev": true }, "jake": { - "version": "10.6.1", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.6.1.tgz", - "integrity": "sha512-pHUK3+V0BjOb1XSi95rbBksrMdIqLVC9bJqDnshVyleYsET3H0XAq+3VB2E3notcYvv4wRdRHn13p7vobG+wfQ==", + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", + "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", "dev": true, "requires": { "async": "0.9.x", @@ -1202,9 +1202,9 @@ } }, "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -1284,9 +1284,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true, "optional": true }, @@ -1302,12 +1302,12 @@ "dev": true }, "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { - "yallist": "^3.0.2" + "yallist": "^4.0.0" } }, "make-dir": { @@ -1319,19 +1319,19 @@ } }, "matcher": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-2.1.0.tgz", - "integrity": "sha512-o+nZr+vtJtgPNklyeUKkkH42OsK8WAfdgaJE2FNxcjLPg+5QbeEoT6vRj8Xq/iv18JlQ9cmKsEu0b94ixWf1YQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", "dev": true, "optional": true, "requires": { - "escape-string-regexp": "^2.0.0" + "escape-string-regexp": "^4.0.0" } }, "mime": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz", - "integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==", + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", "dev": true }, "mimic-fn": { @@ -1432,9 +1432,9 @@ } }, "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "requires": { "mimic-fn": "^2.1.0" } @@ -1605,9 +1605,9 @@ } }, "registry-auth-token": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.1.1.tgz", - "integrity": "sha512-9bKS7nTl9+/A1s7tnPeGrUpRcVY+LUh7bfFgzpndALdPfXQBfQV77rQVtqgUV3ti4vc/Ik81Ex8UJDWDQ12zQA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.0.tgz", + "integrity": "sha512-P+lWzPrsgfN+UEpDS3U8AQKg/UjZX6mQSJueZj3EK+vNESoqBSpBUD3gmu4sF9lOsjXWjF11dQKUqemf3veq1w==", "dev": true, "requires": { "rc": "^1.2.8" @@ -1724,19 +1724,19 @@ } }, "serialize-error": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-5.0.0.tgz", - "integrity": "sha512-/VtpuyzYf82mHYTtI4QKtwHa79vAdU5OQpNPAmE/0UDdlGT0ZxHwC+J6gXkw29wwoVI8fMPsfcVHOwXtUQYYQA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", "dev": true, "optional": true, "requires": { - "type-fest": "^0.8.0" + "type-fest": "^0.13.1" }, "dependencies": { "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", "dev": true, "optional": true } @@ -1770,9 +1770,9 @@ } }, "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -2148,15 +2148,15 @@ "dev": true }, "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, "yargs": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", - "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, "requires": { "cliui": "^6.0.0", @@ -2169,7 +2169,7 @@ "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^18.1.1" + "yargs-parser": "^18.1.2" }, "dependencies": { "find-up": { diff --git a/package.json b/package.json index ac1adbf..d8306dd 100644 --- a/package.json +++ b/package.json @@ -4,26 +4,26 @@ "type": "git", "url": "https://github.com/mrvnklm/homeassistant-desktop" }, - "version": "1.2.1", + "version": "1.3.0", "description": "Desktop App (Windows / macOS) for Home Assistant built with Electron", "main": "app.js", "scripts": { "start": "electron .", - "build-local": "electron-builder build --mac --win --publish never", - "deploy": "electron-builder build --mac --win --publish always", + "build-local": "electron-builder build --mac --win --ia32 --publish never", + "deploy": "electron-builder build --mac --win --ia32 --publish always", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Marvin Kelm (https://github.com/mrvnklm)", "license": "Apache-2.0", "dependencies": { "auto-launch": "^5.0.5", - "electron-store": "^5.1.1", + "electron-store": "^5.2.0", "electron-traywindow-positioner": "^1.1.0", - "electron-updater": "^4.3.1" + "electron-updater": "^4.3.4" }, "devDependencies": { - "electron": "^8.2.5", - "electron-builder": "^22.6.0" + "electron": "^8.5.0", + "electron-builder": "^22.8.0" }, "build": { "appId": "com.electron.homeassistant-desktop", diff --git a/web/assets/checkmark.css b/web/assets/checkmark.css index 1a0efbf..c55ac1a 100644 --- a/web/assets/checkmark.css +++ b/web/assets/checkmark.css @@ -2,145 +2,146 @@ * Extracted from: SweetAlert * Modified by: Istiak Tridip */ - .success-checkmark { - width: 80px; - height: 80px; - margin: 0 auto; - } - .success-checkmark .check-icon { - width: 80px; - height: 80px; - position: relative; - border-radius: 50%; - box-sizing: content-box; - border: 4px solid #4CAF50; - } - .success-checkmark .check-icon::before { - top: 3px; - left: -2px; - width: 30px; - transform-origin: 100% 50%; - border-radius: 100px 0 0 100px; - } - .success-checkmark .check-icon::after { - top: 0; - left: 30px; - width: 60px; - transform-origin: 0 50%; - border-radius: 0 100px 100px 0; - animation: rotate-circle 4.25s ease-in; - } - .success-checkmark .check-icon::before, .success-checkmark .check-icon::after { - content: ""; - height: 100px; - position: absolute; - background: #FFFFFF; - transform: rotate(-45deg); - } - .success-checkmark .check-icon .icon-line { - height: 5px; - background-color: #4CAF50; - display: block; - border-radius: 2px; - position: absolute; - z-index: 10; - } - .success-checkmark .check-icon .icon-line.line-tip { - top: 46px; - left: 14px; - width: 25px; - transform: rotate(45deg); - animation: icon-line-tip 0.75s; - } - .success-checkmark .check-icon .icon-line.line-long { - top: 38px; - right: 8px; - width: 47px; - transform: rotate(-45deg); - animation: icon-line-long 0.75s; - } - .success-checkmark .check-icon .icon-circle { - top: -4px; - left: -4px; - z-index: 10; - width: 80px; - height: 80px; - border-radius: 50%; - position: absolute; - box-sizing: content-box; - border: 4px solid rgba(76, 175, 80, 0.5); - } - .success-checkmark .check-icon .icon-fix { - top: 8px; - width: 5px; - left: 26px; - z-index: 1; - height: 85px; - position: absolute; - transform: rotate(-45deg); - background-color: #FFFFFF; - } +.success-checkmark { + width: 80px; + height: 80px; + margin: 0 auto; +} +.success-checkmark .check-icon { + width: 80px; + height: 80px; + position: relative; + border-radius: 50%; + box-sizing: content-box; + border: 4px solid #4caf50; +} +.success-checkmark .check-icon::before { + top: 3px; + left: -2px; + width: 30px; + transform-origin: 100% 50%; + border-radius: 100px 0 0 100px; +} +.success-checkmark .check-icon::after { + top: 0; + left: 30px; + width: 60px; + transform-origin: 0 50%; + border-radius: 0 100px 100px 0; + animation: rotate-circle 4.25s ease-in; +} +.success-checkmark .check-icon::before, +.success-checkmark .check-icon::after { + content: ""; + height: 100px; + position: absolute; + background: #ffffff; + transform: rotate(-45deg); +} +.success-checkmark .check-icon .icon-line { + height: 5px; + background-color: #4caf50; + display: block; + border-radius: 2px; + position: absolute; + z-index: 10; +} +.success-checkmark .check-icon .icon-line.line-tip { + top: 46px; + left: 14px; + width: 25px; + transform: rotate(45deg); + animation: icon-line-tip 0.75s; +} +.success-checkmark .check-icon .icon-line.line-long { + top: 38px; + right: 8px; + width: 47px; + transform: rotate(-45deg); + animation: icon-line-long 0.75s; +} +.success-checkmark .check-icon .icon-circle { + top: -4px; + left: -4px; + z-index: 10; + width: 80px; + height: 80px; + border-radius: 50%; + position: absolute; + box-sizing: content-box; + border: 4px solid rgba(76, 175, 80, 0.5); +} +.success-checkmark .check-icon .icon-fix { + top: 8px; + width: 5px; + left: 26px; + z-index: 1; + height: 85px; + position: absolute; + transform: rotate(-45deg); + background-color: #ffffff; +} - @keyframes rotate-circle { - 0% { - transform: rotate(-45deg); - } - 5% { - transform: rotate(-45deg); - } - 12% { - transform: rotate(-405deg); - } - 100% { - transform: rotate(-405deg); - } - } - @keyframes icon-line-tip { - 0% { - width: 0; - left: 1px; - top: 19px; - } - 54% { - width: 0; - left: 1px; - top: 19px; - } - 70% { - width: 50px; - left: -8px; - top: 37px; - } - 84% { - width: 17px; - left: 21px; - top: 48px; - } - 100% { - width: 25px; - left: 14px; - top: 45px; - } - } - @keyframes icon-line-long { - 0% { - width: 0; - right: 46px; - top: 54px; - } - 65% { - width: 0; - right: 46px; - top: 54px; - } - 84% { - width: 55px; - right: 0px; - top: 35px; - } - 100% { - width: 47px; - right: 8px; - top: 38px; - } - } +@keyframes rotate-circle { + 0% { + transform: rotate(-45deg); + } + 5% { + transform: rotate(-45deg); + } + 12% { + transform: rotate(-405deg); + } + 100% { + transform: rotate(-405deg); + } +} +@keyframes icon-line-tip { + 0% { + width: 0; + left: 1px; + top: 19px; + } + 54% { + width: 0; + left: 1px; + top: 19px; + } + 70% { + width: 50px; + left: -8px; + top: 37px; + } + 84% { + width: 17px; + left: 21px; + top: 48px; + } + 100% { + width: 25px; + left: 14px; + top: 45px; + } +} +@keyframes icon-line-long { + 0% { + width: 0; + right: 46px; + top: 54px; + } + 65% { + width: 0; + right: 46px; + top: 54px; + } + 84% { + width: 55px; + right: 0px; + top: 35px; + } + 100% { + width: 47px; + right: 8px; + top: 38px; + } +} diff --git a/web/assets/error.css b/web/assets/error.css new file mode 100644 index 0000000..9975821 --- /dev/null +++ b/web/assets/error.css @@ -0,0 +1,42 @@ +svg { + width: 100px; + display: block; + margin: 40px auto 0; +} +.path { + stroke-dasharray: 1000; + stroke-dashoffset: 0; +} +.path.circle { + -webkit-animation: dash 0.9s ease-in-out; + animation: dash 0.9s ease-in-out; +} +.path.line { + stroke-dashoffset: 1000; + -webkit-animation: dash 0.9s 0.35s ease-in-out forwards; + animation: dash 0.9s 0.35s ease-in-out forwards; +} +p { + text-align: center; + margin: 20px 0 60px; + font-size: 1.1em; +} +p.error { + color: #d06079; +} +@-webkit-keyframes dash { + 0% { + stroke-dashoffset: 1000; + } + 100% { + stroke-dashoffset: 0; + } +} +@keyframes dash { + 0% { + stroke-dashoffset: 1000; + } + 100% { + stroke-dashoffset: 0; + } +} diff --git a/web/assets/style.css b/web/assets/style.css index 76fc9d1..beecf9f 100644 --- a/web/assets/style.css +++ b/web/assets/style.css @@ -1,101 +1,109 @@ body { - font-family: Roboto, sans-serif; - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - font-weight: 400; - margin: 0; - padding: 0; + font-family: Roboto, sans-serif; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + font-weight: 400; + margin: 0; + padding: 0; } #check-wrapper { - display: none; - margin-top: 40px; - margin-bottom: 10px; + display: none; + margin-top: 40px; + margin-bottom: 10px; } .grey { - color: grey; + color: grey; } .content { - padding: 20px 16px; - margin: 0 auto + padding: 20px 16px; + margin: 0 auto; } .header { - font-size: 1.96em; - font-weight: 300; + font-size: 1.96em; + font-weight: 300; } .center { - display: flex; - align-items: center; - justify-content: center; + display: flex; + align-items: center; + justify-content: center; +} + +.vertical-center { + display: flex; + align-items: center; + justify-content: center; + height: 100vh; } p { - padding-top: 20px; - width: 320px; + padding-top: 20px; + width: 320px; } .header img { - margin-right: 16px + margin-right: 16px; } .group { - position: relative; - margin: 45px 0; + position: relative; + margin: 45px 0; } input { - background: none; - font-size: 18px; - padding: 10px 0px 10px 0px; - display: block; - width: 320px; - border: none; - border-radius: 0; - border-bottom: 1px solid #d5d5d5; + background: none; + font-size: 18px; + padding: 10px 0px 10px 0px; + display: block; + width: 320px; + border: none; + border-radius: 0; + border-bottom: 1px solid #d5d5d5; } input:focus { - outline: none; + outline: none; } -input:focus ~ label, input:valid ~ label { - top: -14px; - font-size: 12px; - color: #03a9f4; +input:focus ~ label, +input:valid ~ label { + top: -14px; + font-size: 12px; + color: #03a9f4; } input:focus ~ .bar:before { - width: 320px; + width: 320px; } label { - color: #d5d5d5; - font-size: 16px; - font-weight: normal; - position: absolute; - pointer-events: none; - left: 5px; - top: 10px; - transition: 300ms ease all; + color: #d5d5d5; + font-size: 16px; + font-weight: normal; + position: absolute; + pointer-events: none; + left: 5px; + top: 10px; + transition: 300ms ease all; } .bar { - position: relative; - display: block; - width: 320px; + position: relative; + display: block; + width: 320px; } .bar:before { - content: ""; - height: 2px; - width: 0; - bottom: 0px; - position: absolute; - background: #03a9f4; - transition: 300ms ease all; - left: 0%; + content: ""; + height: 2px; + width: 0; + bottom: 0px; + position: absolute; + background: #03a9f4; + transition: 300ms ease all; + left: 0%; } diff --git a/web/error.html b/web/error.html new file mode 100644 index 0000000..658e8b3 --- /dev/null +++ b/web/error.html @@ -0,0 +1,65 @@ + + +
++ Home Assistant instance is not available, please check your + connection. +
+Please enter your Home Assistant URL in the field below:
Please enter your Home Assistant URL in the field below:
++ If the entered URL directs to a working Home Assistant instance, + you will be forwarded to the login page automatically. +
+If the entered URL directs to a working Home Assistant instance, you will be forwarded to the login page automatically.
-