production-taskbar-client / src / main / ipc / speedometerChannel.js
speedometerChannel.js
Raw
import path from "path";
import { BrowserWindow, app, screen, ipcMain } from "electron";
import log from "electron-log";

import settings from "../settings";
import { getHostname } from "../utils/os";
import openDevToolsWindow from "../utils/openDevToolsWindow";
import setWindowBouns from "../utils/setWindowBounds";

const isDev = process.env.NODE_ENV === "development";
const baseUrl = new URL(process.env.DATA_ACQUISITION_URL);
let url = `${baseUrl.href}sebn-speedometer-next/dashboard/${getHostname()}/`;
if (isDev)
  url = `http://127.0.0.1:3000/speedometer/dashboard/${getHostname()}/`;

const kSpeedometerBoundsSettings = "speedometerBoundsSettings";
const kSpeedometerEnableSetting = "speedometerEnable";
let speedometerWindow;
let speedometerDevToolsWindow;

export default async function initSpeedometerChannel(mainWindow) {
  const defaultWidth = 240;
  const enableSetting = settings.get(kSpeedometerEnableSetting, false);

  const getSpeedometerBoundsSettings = () => {
    const { width: screenWidth, height: screenHeight } =
      screen.getPrimaryDisplay().size;
    const defaultX = screenWidth - defaultWidth;
    const defaultY = screenHeight / 2 - defaultWidth / 2;

    const speedometerSettings = settings.get(kSpeedometerBoundsSettings);
    if (speedometerSettings) {
      let { x: sX, y: sY, w: sW, h: sH } = speedometerSettings;

      sX = parseInt(sX, 10);
      sY = parseInt(sY, 10);
      sW = parseInt(sW, 10);
      sH = parseInt(sH, 10);
      const isBoundsValid = sX && sY && sW && sH;
      if (isBoundsValid) {
        sX = sX > defaultX || sX < 0 ? Math.floor(defaultX - 1) : sX;
        sY =
          sY > screenHeight - defaultWidth || sY < 0
            ? Math.floor(defaultY - 1)
            : sY;
        sW = defaultWidth;
        sH = defaultWidth;
        return { x: sX, y: sY, width: sW, height: sH };
      }
    }

    return {
      x: defaultX,
      y: defaultY,
      width: defaultWidth,
      height: defaultWidth,
    };
  };

  const createSpeedometerWindow = async () => {
    const { x, y, width, height } = getSpeedometerBoundsSettings();

    const win = new BrowserWindow({
      x,
      y,
      width,
      height,
      minWidth: width,
      maxWidth: width,
      minHeight: height,
      type: "toolbar",
      skipTaskbar: true,
      hasShadow: false,
      fullscreenable: false,
      maximizable: false,
      minimizable: false,
      resizable: true,
      movable: true,
      thickFrame: false,
      titleBarStyle: "hidden",
      transparent: true,
      alwaysOnTop: true,
      frame: false,
      show: false,
      webPreferences: {
        preload: path.join(app.getAppPath(), "./dist/preload.js"),
        nodeIntegration: true,
        contextIsolation: false,
        backgroundThrottling: false,
        enablePreferredSizeMode: true,
        devTools: isDev,
        additionalArguments: ["speedometer"],
      },
    });

    win.once("ready-to-show", () => {
      win.showInactive();
      win.setAlwaysOnTop(true, "status");
    });

    win.on("moved", () => {
      const {
        x: newX,
        y: newY,
        width: newW,
        height: newH,
      } = setWindowBouns(win);
      settings.set(kSpeedometerBoundsSettings, {
        x: newX,
        y: newY,
        w: newW,
        h: newH,
      });
    });

    win.webContents.on(
      "preferred-size-changed",
      (event, { width: w, height: h }) => {
        const { height: screenHeight } = screen.getPrimaryDisplay().size;
        win.setSize(
          w >= defaultWidth ? defaultWidth : w,
          h >= screenHeight ? screenHeight - 100 : h
        );
      }
    );

    win.on("closed", () => {
      speedometerWindow = null;
      mainWindow.webContents.send("speedometer", { event: "closed" });
      if (!speedometerDevToolsWindow?.isDestroyed())
        speedometerDevToolsWindow?.close();
    });

    win.webContents.once(
      "did-fail-load",
      (_event, errorCode, errorDescription, validatedURL) => {
        win.close();
        log.error(
          `Speedometer failed to load ${validatedURL}. ${errorCode}: ${errorDescription}`
        );
      }
    );

    if (isDev) {
      win.webContents.once("did-finish-load", () => {
        speedometerDevToolsWindow = openDevToolsWindow({
          window: win,
          title: "Speedometer",
        });
      });
    }

    await win.loadURL(url);

    return win;
  };

  ipcMain.handle("speedometer", async (_e, { event }) => {
    switch (event) {
      case "open":
        if (!speedometerWindow) {
          speedometerWindow = await createSpeedometerWindow();
          settings.set(kSpeedometerEnableSetting, true);
        }
        return true;
      case "close":
        speedometerWindow?.destroy();
        return false;
      case "toggle":
        if (speedometerWindow) {
          speedometerWindow?.destroy();
          settings.set(kSpeedometerEnableSetting, false);
          return false;
        }
        speedometerWindow = await createSpeedometerWindow();
        settings.set(kSpeedometerEnableSetting, true);
        return true;
      case "is-open":
        return !!speedometerWindow;
      default:
        return false;
    }
  });

  if (enableSetting) {
    speedometerWindow = await createSpeedometerWindow();
  }
}