mirror of
https://github.com/sascha-hemi/homeassistant-desktop.git
synced 2026-03-21 00:04:12 +01:00
275 lines
8.1 KiB
JavaScript
275 lines
8.1 KiB
JavaScript
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');
|
|
|
|
app.allowRendererProcessReuse = true;
|
|
|
|
// prevent multiple instances
|
|
if (!app.requestSingleInstanceLock()) {
|
|
app.quit()
|
|
} else {
|
|
app.on('second-instance', () => {
|
|
if (window) showWindow();
|
|
})
|
|
}
|
|
|
|
// hide dock icon on macOS
|
|
if (process.platform === 'darwin') app.dock.hide();
|
|
|
|
const store = new Store();
|
|
const autoLauncher = new AutoLaunch({name: 'Home Assistant Desktop'});
|
|
|
|
let autostartEnabled = false;
|
|
let forceQuit = false;
|
|
|
|
if (process.argv[1] === '--squirrel-firstrun') autoLauncher.enable();
|
|
|
|
const useAutoUpdater = () => {
|
|
autoUpdater.on('error', message => {
|
|
console.error('There was a problem updating the application');
|
|
console.error(message)
|
|
});
|
|
autoUpdater.checkForUpdatesAndNotify();
|
|
};
|
|
|
|
const checkAutoStart = () => {
|
|
autoLauncher.isEnabled().then((isEnabled) => {
|
|
autostartEnabled = isEnabled;
|
|
}).catch((err) => {
|
|
console.error(err)
|
|
});
|
|
};
|
|
|
|
const getMenu = () => {
|
|
return Menu.buildFromTemplate([
|
|
{
|
|
label: (store.has('instance') ? store.get('instance').name : 'Not connected...'),
|
|
enabled: !!store.has('instance'),
|
|
click: () => {
|
|
shell.openExternal(store.get('instance').url)
|
|
}
|
|
}, {
|
|
type: 'separator'
|
|
},
|
|
{
|
|
label: 'Hover to Show',
|
|
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'));
|
|
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: '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();
|
|
}
|
|
}
|
|
])
|
|
};
|
|
|
|
const createMainWindow = (show = false) => {
|
|
window = new BrowserWindow({
|
|
width: 420,
|
|
height: 420,
|
|
show: false,
|
|
skipTaskbar: true,
|
|
autoHideMenuBar: true,
|
|
frame: false,
|
|
webPreferences: {
|
|
nodeIntegration: true
|
|
}
|
|
});
|
|
|
|
if (store.get('detachedMode')) {
|
|
if (!store.has('windowPosition')) store.set('windowPosition', window.getPosition());
|
|
if (!store.has('windowSizeDetached')) store.set('windowSizeDetached', window.getSize())
|
|
} else {
|
|
if (!store.has('windowSize')) store.set('windowSize', window.getSize())
|
|
}
|
|
|
|
window.loadURL(`file://${__dirname}/web/index.html`)
|
|
|
|
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')) {
|
|
window.setSize(...store.get('windowSizeDetached'));
|
|
window.setPosition(...store.get('windowPosition'))
|
|
} else {
|
|
window.setSize(...store.get('windowSize'))
|
|
}
|
|
|
|
window.on('resize', () => {
|
|
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('close', (e) => {
|
|
if (!forceQuit) {
|
|
window.hide();
|
|
e.preventDefault()
|
|
}
|
|
});
|
|
|
|
window.on('blur', () => {
|
|
if (!store.get('detachedMode') && !window.isAlwaysOnTop()) window.hide();
|
|
});
|
|
|
|
if (show) showWindow();
|
|
};
|
|
|
|
const showWindow = () => {
|
|
if (!store.get('detachedMode')) Positioner.position(window, tray.getBounds());
|
|
if (!window.isVisible()) {
|
|
window.show();
|
|
window.focus();
|
|
}
|
|
};
|
|
|
|
const createTray = () => {
|
|
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('right-click', () => {
|
|
window.hide();
|
|
tray.popUpContextMenu(getMenu())
|
|
});
|
|
|
|
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);
|
|
}
|
|
)
|
|
}
|
|
;
|
|
|
|
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)
|
|
};
|
|
|
|
app.on('ready', () => {
|
|
useAutoUpdater();
|
|
createTray();
|
|
createMainWindow(!store.has('instance'));
|
|
});
|
|
|
|
ipcMain.on('ha-instance', (event, args) => {
|
|
if (args) {
|
|
store.set('instance', args)
|
|
} else {
|
|
event.reply('ha-instance', store.get('instance'))
|
|
}
|
|
});
|