import path from "path"; import { app, BrowserWindow, screen, ipcMain } from "electron"; import installDevExtensions from "./utils/installDevExtensions"; import { registerAppBar } from "./utils/registerWinAppBar"; import settings from "./settings"; import openDevToolsWindow from "./utils/openDevToolsWindow"; import setWindowBouns from "./utils/setWindowBounds"; const kMainWindowChannel = "mainWindow"; const isDev = process.env.NODE_ENV === "development"; const defaultFloatingWidth = 350; const defaultFloatingHeight = 100; const setBounds = (window) => { const { isAutoHide } = window; // eslint-disable-next-line prefer-const const { x, y, width, height } = setWindowBouns(window); settings.set("mainWindowSettings", { isFloating: true, isHide: false, isAutoHide, x, y, w: width, h: height, }); }; const getBounds = () => { const mainWindowSettings = settings.get("mainWindowSettings"); if (mainWindowSettings) { // eslint-disable-next-line prefer-const let { isFloating, isHide, isAutoHide, x, y, w, h } = mainWindowSettings; const { width: screenWidth, height: screenHeight } = screen.getPrimaryDisplay().size; x = parseInt(x, 10); y = parseInt(y, 10); w = parseInt(w, 10); h = parseInt(h, 10); const isBoundsValid = x && y && w && h; if (!isBoundsValid) { x = screenWidth - defaultFloatingWidth - 1; y = screenHeight - defaultFloatingHeight - 1; w = defaultFloatingWidth; h = defaultFloatingHeight; } if (typeof isFloating === "boolean") { isHide = typeof isHide === "boolean" ? isHide : false; isAutoHide = typeof isAutoHide === "boolean" ? isAutoHide : false; if (isFloating) { return { x, y, w, h, isHide, isAutoHide }; } } else { settings.delete("mainWindowSettings"); } } return null; }; async function createTaskbarWindow(params = undefined) { let x; let y; let width; let height = 80; const isShow = false; let isHide = false; let isAutoHide = false; let isToggling = false; let isMovable = isDev; let isResizable = isDev; let maxHeight = 80; let minHeight = 50; const toggleButtonWidth = 30; // must be same as [ToggleButton.less => @width] let maxWidth = 600 + toggleButtonWidth; const minWidth = 300 + toggleButtonWidth; if (params) { ({ x, y, w: width, h: height, isHide, isAutoHide } = params); isMovable = true; isResizable = true; maxHeight = 150; minHeight = 100; } else { const { width: screenWidth, height: screenHeight } = isDev ? screen.getPrimaryDisplay().workAreaSize : screen.getPrimaryDisplay().size; width = screenWidth; maxWidth = screenWidth; x = 0; y = screenHeight - height; } //* Real position applies in [registerAppBar] when windows send a resize after a new appbar is added. //* If set size right now, the windows resize comes last and overrides us. let win = new BrowserWindow({ x, y, width, height, show: isShow, minHeight, maxHeight, minWidth, maxWidth, type: "toolbar", closable: false, skipTaskbar: true, hasShadow: false, fullscreenable: false, maximizable: false, minimizable: false, movable: isMovable, thickFrame: false, titleBarStyle: "hidden", transparent: true, alwaysOnTop: true, frame: false, resizable: isResizable, webPreferences: { preload: path.join(app.getAppPath(), "./dist/preload.js"), nodeIntegration: true, contextIsolation: false, backgroundThrottling: false, devTools: isDev, additionalArguments: ["mainWindow"], }, }); const toggleWin = (hide) => { if (!isToggling) { isToggling = true; const intervalDelay = 10; const offsetX = 80; const { width: screenWidth } = screen.getPrimaryDisplay().size; let { x: currentX, y: currentY } = win.getBounds(); const { x: savedX, y: savedY, w: savedW, h: savedH } = getBounds(); currentX = Math.round(currentX); currentY = Math.round(currentY); const leftPos = screenWidth - toggleButtonWidth; if (hide) { // Hiding animation interval isHide = true; const interval = setInterval(() => { currentX += offsetX; if (currentX >= screenWidth) { clearInterval(interval); win.setBounds({ x: leftPos, y: currentY, width: savedW, height: savedH, }); settings.set("mainWindowSettings", { isFloating: true, isHide: true, isAutoHide, x: savedX, y: savedY, w: savedW, h: savedH, }); } else { win.setBounds({ x: currentX, y: currentY, width: savedW, height: savedH, }); } isToggling = false; win.blur(); }, intervalDelay); } else { // Showing animation interval isHide = false; const interval = setInterval(() => { currentX -= offsetX; if (currentX <= savedX) { clearInterval(interval); win.setBounds({ x: savedX, y: currentY, width: savedW, height: savedH, }); settings.set("mainWindowSettings", { isFloating: true, isHide: false, isAutoHide, x: savedX, y: savedY, w: savedW, h: savedH, }); } else { win.setBounds({ x: currentX, y: currentY, width: savedW, height: savedH, }); } isToggling = false; }, intervalDelay); } } }; win.on("closed", () => { win = null; }); win.on("blur", () => { if (isAutoHide) { toggleWin(true); win.webContents.send(kMainWindowChannel, { event: "set-ishide", data: isHide, }); } }); win.once("ready-to-show", () => { if (!params && process.platform === "win32") { registerAppBar(win); // and show window after } win.setAlwaysOnTop(true, "screen-saver"); win.showInactive(); if (isHide) { toggleWin(isHide); } }); win.on("moved", () => { setBounds(win); }); win.on("resized", () => setBounds(win)); ipcMain.handle(kMainWindowChannel, async (_e, { event, data }) => { switch (event) { case "toggle-win": toggleWin(data); return true; case "get-toggle-settings": return { isHide, isAutoHide }; case "set-autohide": { isAutoHide = data; win.isAutoHide = data; // use win to access isAutoHide on saving settings on move const mainWindowSettings = settings.get("mainWindowSettings"); mainWindowSettings.isAutoHide = data; settings.set("mainWindowSettings", mainWindowSettings); return true; } case "get-autohide": return isAutoHide; default: return false; } }); // loadURL after init event listeners if (isDev) { process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = "false"; await installDevExtensions(); let url = "http://localhost:4000"; if (params) url = `http://localhost:4000#/compact`; await win.loadURL(url); openDevToolsWindow({ window: win, title: kMainWindowChannel }); // Reopen fix redux extenstion [No Store Found] after hot reload win.webContents.on("devtools-closed", () => setTimeout( () => openDevToolsWindow({ window: win, title: kMainWindowChannel }), 500 ) ); } else { let url = `file://${app.getAppPath()}/dist/renderer/index.html`; if (params) url = `file://${app.getAppPath()}/dist/renderer/index.html#/compact`; win.loadURL(url); } return win; } export default async function getTaskbarWindow() { const bounds = getBounds(); if (bounds) return createTaskbarWindow(bounds); return createTaskbarWindow(); }