production-taskbar-client / src / renderer / features / programs / program_button / ProgramButton.jsx
ProgramButton.jsx
Raw
/* eslint-disable react/destructuring-assignment */
/* eslint-disable camelcase */

import { ipcRenderer } from "electron";
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Button, Tooltip } from "antd";
import { useTranslation } from "react-i18next";

import { setProgramNotExist } from "../programsSlice";
import ImageButton from "../../../app/components/image_button/ImageButton";
import { IconTag } from "../../../apis/cache";
import useLongPressRestart from "./useLongPressRestart";

import "./ProgramButton.less";

// dont use import from main due bundle isolation
const kUrl = "openUrl";
const kFile = "openProgram";
const kCloseFile = "closeProgram";
const kForegroundError = "exec-foreground-error";
const kError = "exec-error";
const kNotExist = "not-exist";

export default (props) => {
  const dispatch = useDispatch();
  const [tooltipTitle, useTooltipTitle] = useState({
    visible: false,
    title: "",
  });
  const notExistedPrograms = useSelector(
    (state) => state.programs.programsNotExist
  );
  const isCompact = useSelector((state) => state.taskbar.compact);

  const { type, program, active } = props;
  const { name, label, description, order } = program;
  useEffect(
    () => useTooltipTitle({ visible: false, title: description }),
    [description]
  );
  const { t } = useTranslation();

  const iconUrl = useSelector(
    (state) => state.cache.attachments[`workplace_${name}_${IconTag}`]
  );

  let runProgram;
  let closeProgram;
  let notExist = false;

  const handleResult = (result) => {
    switch (result) {
      case kForegroundError:
        break;
      case kError:
        break;
      case kNotExist:
        dispatch(setProgramNotExist(program));
        break;
      default:
        break;
    }
  };

  if (type === "program") {
    const { executable_path, fallback_path, window_process, parameters } =
      props.program;

    runProgram = async () => {
      const result = await ipcRenderer.invoke(kFile, {
        file: executable_path,
        fallback_path,
        params: parameters,
        windowProcess: window_process,
      });
      handleResult(result);
    };

    closeProgram = async () => {
      await ipcRenderer.invoke(kCloseFile, {
        file: executable_path,
        fallback_path,
        windowProcess: window_process,
      });
    };
  } else if (type === "exclusive") {
    const { executable_path, fallback_path } = props.program;

    runProgram = async () => {
      const result = await ipcRenderer.invoke(kFile, {
        file: executable_path,
        fallback_path,
        params: null,
      });
      handleResult(result);
    };
    closeProgram = async () => {
      await ipcRenderer.invoke(kCloseFile, {
        file: executable_path,
        fallback_path,
      });
    };
  } else if (type === "web") {
    const { url, open_with_default_browser, is_frameless } = props.program;
    runProgram = async () => {
      const result = await ipcRenderer.invoke(kUrl, {
        title: name,
        url,
        fullscreen: true,
        frameless: is_frameless,
        openDefaultBrowser: open_with_default_browser,
      });
      handleResult(result);
    };
  }

  if (notExistedPrograms.find((e) => e === name)) {
    notExist = true;
  }

  const { events } = useLongPressRestart(
    () => {
      if (type === "program" || type === "exclusive")
        useTooltipTitle({ visible: true, title: t("programRestarting") });
    },
    async () => {
      if (type === "program" || type === "exclusive") {
        setTimeout(
          () => useTooltipTitle({ visible: false, title: description }),
          100
        );
        await closeProgram();
        runProgram();
      }
    },
    2000
  );

  return (
    <Tooltip
      open={tooltipTitle.visible}
      placement="right"
      title={tooltipTitle.title}
      className={isCompact ? "program-button--compact" : "program-button"}
    >
      {iconUrl ? (
        <ImageButton
          key={name}
          text={label || name}
          iconUrl={iconUrl}
          order={order}
          callback={() => {
            if (!tooltipTitle.visible) runProgram();
          }}
          active={active}
          events={events}
        />
      ) : (
        <Button
          danger={notExist}
          style={{ order }}
          onClick={() => {
            if (!tooltipTitle.visible) runProgram();
          }}
          // eslint-disable-next-line react/jsx-props-no-spreading
          {...events}
        >
          {label || name}
        </Button>
      )}
    </Tooltip>
  );
};