瀏覽代碼

fix: unified switch style

MystiPanda 10 月之前
父節點
當前提交
4cd7ccda57

+ 1 - 0
src/components/base/base-switch.tsx

@@ -11,6 +11,7 @@ export const Switch = styled((props: SwitchProps) => (
   width: 42,
   height: 26,
   padding: 0,
+  marginRight: 1,
   "& .MuiSwitch-switchBase": {
     padding: 0,
     margin: 2,

+ 97 - 0
src/components/setting/mods/service-switcher.tsx

@@ -0,0 +1,97 @@
+import { KeyedMutator } from "swr";
+import { useState } from "react";
+import { useLockFn } from "ahooks";
+import { useTranslation } from "react-i18next";
+import { installService, uninstallService } from "@/services/cmds";
+import { Notice } from "@/components/base";
+import { LoadingButton } from "@mui/lab";
+
+interface Props {
+  status: "active" | "installed" | "unknown" | "uninstall";
+  mutate: KeyedMutator<"active" | "installed" | "unknown" | "uninstall">;
+  patchVerge: (value: Partial<IVergeConfig>) => Promise<void>;
+  onChangeData: (patch: Partial<IVergeConfig>) => void;
+}
+
+export const ServiceSwitcher = (props: Props) => {
+  const { status, mutate, patchVerge, onChangeData } = props;
+
+  const isActive = status === "active";
+  const isInstalled = status === "installed";
+  const isUninstall = status === "uninstall" || status === "unknown";
+
+  const { t } = useTranslation();
+  const [serviceLoading, setServiceLoading] = useState(false);
+  const [uninstallServiceLoaing, setUninstallServiceLoading] = useState(false);
+
+  const onInstallOrEnableService = useLockFn(async () => {
+    setServiceLoading(true);
+    try {
+      if (isUninstall) {
+        // install service
+        await installService();
+        await mutate();
+        setTimeout(() => {
+          mutate();
+        }, 2000);
+        Notice.success(t("Service Installed Successfully"));
+        setServiceLoading(false);
+      } else {
+        // enable or disable service
+        await patchVerge({ enable_service_mode: !isActive });
+        onChangeData({ enable_service_mode: !isActive });
+        await mutate();
+        setTimeout(() => {
+          mutate();
+        }, 2000);
+        setServiceLoading(false);
+      }
+    } catch (err: any) {
+      await mutate();
+      Notice.error(err.message || err.toString());
+      setServiceLoading(false);
+    }
+  });
+
+  const onUninstallService = useLockFn(async () => {
+    setUninstallServiceLoading(true);
+    try {
+      await uninstallService();
+      await mutate();
+      setTimeout(() => {
+        mutate();
+      }, 2000);
+      Notice.success(t("Service Uninstalled Successfully"));
+      setUninstallServiceLoading(false);
+    } catch (err: any) {
+      await mutate();
+      Notice.error(err.message || err.toString());
+      setUninstallServiceLoading(false);
+    }
+  });
+
+  return (
+    <>
+      <LoadingButton
+        size="small"
+        variant={isUninstall ? "outlined" : "contained"}
+        onClick={onInstallOrEnableService}
+        loading={serviceLoading}
+      >
+        {isActive ? t("Disable") : isInstalled ? t("Enable") : t("Install")}
+      </LoadingButton>
+      {isInstalled && (
+        <LoadingButton
+          size="small"
+          variant="outlined"
+          color="error"
+          sx={{ ml: 1 }}
+          onClick={onUninstallService}
+          loading={uninstallServiceLoaing}
+        >
+          {t("Uninstall")}
+        </LoadingButton>
+      )}
+    </>
+  );
+};

+ 0 - 129
src/components/setting/mods/service-viewer.tsx

@@ -1,129 +0,0 @@
-import useSWR from "swr";
-import { forwardRef, useImperativeHandle, useState } from "react";
-import { useLockFn } from "ahooks";
-import { useTranslation } from "react-i18next";
-import { Button, Stack, Typography } from "@mui/material";
-import {
-  checkService,
-  installService,
-  uninstallService,
-  patchVergeConfig,
-} from "@/services/cmds";
-import { BaseDialog, DialogRef, Notice } from "@/components/base";
-
-interface Props {
-  enable: boolean;
-}
-
-export const ServiceViewer = forwardRef<DialogRef, Props>((props, ref) => {
-  const { enable } = props;
-
-  const { t } = useTranslation();
-  const [open, setOpen] = useState(false);
-
-  const { data: status, mutate: mutateCheck } = useSWR(
-    "checkService",
-    checkService,
-    {
-      revalidateIfStale: false,
-      shouldRetryOnError: false,
-      focusThrottleInterval: 36e5, // 1 hour
-    }
-  );
-
-  useImperativeHandle(ref, () => ({
-    open: () => setOpen(true),
-    close: () => setOpen(false),
-  }));
-
-  const state = status != null ? status : "pending";
-
-  const onInstall = useLockFn(async () => {
-    try {
-      await installService();
-      await mutateCheck();
-      setOpen(false);
-      setTimeout(() => {
-        mutateCheck();
-      }, 2000);
-      Notice.success(t("Service Installed Successfully"));
-    } catch (err: any) {
-      mutateCheck();
-      Notice.error(err.message || err.toString());
-    }
-  });
-
-  const onUninstall = useLockFn(async () => {
-    try {
-      if (enable) {
-        await patchVergeConfig({ enable_service_mode: false });
-      }
-
-      await uninstallService();
-      mutateCheck();
-      setOpen(false);
-      Notice.success(t("Service Uninstalled Successfully"));
-    } catch (err: any) {
-      mutateCheck();
-      Notice.error(err.message || err.toString());
-    }
-  });
-
-  // fix unhandled error of the service mode
-  const onDisable = useLockFn(async () => {
-    try {
-      await patchVergeConfig({ enable_service_mode: false });
-      mutateCheck();
-      setOpen(false);
-    } catch (err: any) {
-      mutateCheck();
-      Notice.error(err.message || err.toString());
-    }
-  });
-
-  return (
-    <BaseDialog
-      open={open}
-      title={t("Service Mode")}
-      contentSx={{ width: 360, userSelect: "text" }}
-      disableFooter
-      onClose={() => setOpen(false)}
-    >
-      <Typography>
-        {t("Current State")}: {t(state)}
-      </Typography>
-
-      {(state === "unknown" || state === "uninstall") && (
-        <Typography>
-          {t(
-            "Information: Please make sure that the Clash Verge Service is installed and enabled"
-          )}
-        </Typography>
-      )}
-
-      <Stack
-        direction="row"
-        spacing={1}
-        sx={{ mt: 4, justifyContent: "flex-end" }}
-      >
-        {state === "uninstall" && enable && (
-          <Button variant="contained" onClick={onDisable}>
-            {t("Disable Service Mode")}
-          </Button>
-        )}
-
-        {state === "uninstall" && (
-          <Button variant="contained" onClick={onInstall}>
-            {t("Install")}
-          </Button>
-        )}
-
-        {(state === "active" || state === "installed") && (
-          <Button variant="outlined" onClick={onUninstall}>
-            {t("Uninstall")}
-          </Button>
-        )}
-      </Stack>
-    </BaseDialog>
-  );
-});

+ 10 - 87
src/components/setting/setting-system.tsx

@@ -1,22 +1,16 @@
 import useSWR from "swr";
-import { useRef, useState } from "react";
+import { useRef } from "react";
 import { useTranslation } from "react-i18next";
 import { SettingsRounded } from "@mui/icons-material";
-import {
-  checkService,
-  installService,
-  uninstallService,
-} from "@/services/cmds";
+import { checkService } from "@/services/cmds";
 import { useVerge } from "@/hooks/use-verge";
 import { DialogRef, Notice, Switch } from "@/components/base";
 import { SettingList, SettingItem } from "./mods/setting-comp";
 import { GuardState } from "./mods/guard-state";
-import { ServiceViewer } from "./mods/service-viewer";
+import { ServiceSwitcher } from "./mods/service-switcher";
 import { SysproxyViewer } from "./mods/sysproxy-viewer";
 import { TunViewer } from "./mods/tun-viewer";
 import { TooltipIcon } from "@/components/base/base-tooltip-icon";
-import { LoadingButton } from "@mui/lab";
-import { useLockFn } from "ahooks";
 
 interface Props {
   onError?: (err: Error) => void;
@@ -26,8 +20,6 @@ const SettingSystem = ({ onError }: Props) => {
   const { t } = useTranslation();
 
   const { verge, mutateVerge, patchVerge } = useVerge();
-  const [serviceLoading, setServiceLoading] = useState(false);
-  const [uninstallServiceLoaing, setUninstallServiceLoading] = useState(false);
   // service mode
   const { data: serviceStatus, mutate: mutateServiceStatus } = useSWR(
     "checkService",
@@ -39,14 +31,12 @@ const SettingSystem = ({ onError }: Props) => {
     }
   );
 
-  const serviceRef = useRef<DialogRef>(null);
   const sysproxyRef = useRef<DialogRef>(null);
   const tunRef = useRef<DialogRef>(null);
 
   const {
     enable_tun_mode,
     enable_auto_launch,
-    enable_service_mode,
     enable_silent_start,
     enable_system_proxy,
   } = verge ?? {};
@@ -56,58 +46,10 @@ const SettingSystem = ({ onError }: Props) => {
     mutateVerge({ ...verge, ...patch }, false);
   };
 
-  const onInstallOrEnableService = useLockFn(async () => {
-    setServiceLoading(true);
-    try {
-      if (serviceStatus === "uninstall" || serviceStatus === "unknown") {
-        // install service
-        await installService();
-        await mutateServiceStatus();
-        setTimeout(() => {
-          mutateServiceStatus();
-        }, 2000);
-        Notice.success(t("Service Installed Successfully"));
-        setServiceLoading(false);
-      } else {
-        // enable or disable service
-        const enable = serviceStatus === "active";
-        await patchVerge({ enable_service_mode: !enable });
-        onChangeData({ enable_service_mode: !enable });
-        await mutateServiceStatus();
-        setTimeout(() => {
-          mutateServiceStatus();
-        }, 2000);
-        setServiceLoading(false);
-      }
-    } catch (err: any) {
-      await mutateServiceStatus();
-      Notice.error(err.message || err.toString());
-      setServiceLoading(false);
-    }
-  });
-
-  const onUninstallService = useLockFn(async () => {
-    setUninstallServiceLoading(true);
-    try {
-      await uninstallService();
-      await mutateServiceStatus();
-      setTimeout(() => {
-        mutateServiceStatus();
-      }, 2000);
-      Notice.success(t("Service Uninstalled Successfully"));
-      setUninstallServiceLoading(false);
-    } catch (err: any) {
-      await mutateServiceStatus();
-      Notice.error(err.message || err.toString());
-      setUninstallServiceLoading(false);
-    }
-  });
-
   return (
     <SettingList title={t("System Setting")}>
       <SysproxyViewer ref={sysproxyRef} />
       <TunViewer ref={tunRef} />
-      <ServiceViewer ref={serviceRef} enable={!!enable_service_mode} />
 
       <SettingItem
         label={t("Tun Mode")}
@@ -133,7 +75,7 @@ const SettingSystem = ({ onError }: Props) => {
           }}
           onGuard={(e) => {
             if (serviceStatus !== "active" && e) {
-              Notice.error(t("Please enable service mode first"));
+              Notice.error(t("Please Enable Service Mode"));
               return Promise.resolve();
             } else {
               return patchVerge({ enable_tun_mode: e });
@@ -145,31 +87,12 @@ const SettingSystem = ({ onError }: Props) => {
       </SettingItem>
 
       <SettingItem label={t("Service Mode")}>
-        <LoadingButton
-          size="small"
-          variant="contained"
-          sx={{ mr: serviceStatus !== "installed" ? -1 : 0 }}
-          onClick={onInstallOrEnableService}
-          loading={serviceLoading}
-        >
-          {serviceStatus === "active"
-            ? t("Disable")
-            : serviceStatus === "installed"
-            ? t("Enable")
-            : t("Install")}
-        </LoadingButton>
-        {serviceStatus === "installed" && (
-          <LoadingButton
-            size="small"
-            variant="outlined"
-            color="error"
-            sx={{ ml: 1, mr: -1 }}
-            onClick={onUninstallService}
-            loading={uninstallServiceLoaing}
-          >
-            {t("Uninstall")}
-          </LoadingButton>
-        )}
+        <ServiceSwitcher
+          status={serviceStatus ?? "unknown"}
+          mutate={mutateServiceStatus}
+          patchVerge={patchVerge}
+          onChangeData={onChangeData}
+        />
       </SettingItem>
 
       <SettingItem

+ 1 - 1
src/locales/en.json

@@ -266,7 +266,7 @@
   "Restart": "Restart",
   "Release Version": "Release Version",
   "Alpha Version": "Alpha Version",
-  "Tun mode requires": "Tun mode requires",
+  "Please Enable Service Mode": "Please Install and Enable Service Mode First",
   "Grant": "Grant",
   "Open UWP tool": "Open UWP tool",
   "Open UWP tool Info": "Since Windows 8, UWP apps (such as Microsoft Store) are restricted from directly accessing local host network services, and this tool can be used to bypass this restriction",

+ 1 - 1
src/locales/fa.json

@@ -261,7 +261,7 @@
   "Restart": "راه‌اندازی مجدد",
   "Release Version": "نسخه نهایی",
   "Alpha Version": "نسخه آلفا",
-  "Tun mode requires": "Tun mode نیاز دارد",
+  "Please Install and Enable Service Mode First": "لطفاً ابتدا حالت سرویس را نصب و فعال کنید",
   "Grant": "اعطا",
   "Open UWP tool": "باز کردن ابزار UWP",
   "Open UWP tool Info": "از ویندوز 8 به بعد، برنامه‌های UWP (مانند Microsoft Store) از دسترسی مستقیم به خدمات شبکه محلی محدود شده‌اند و این ابزار می‌تواند برای دور زدن این محدودیت استفاده شود",

+ 1 - 1
src/locales/ru.json

@@ -264,7 +264,7 @@
   "Restart": "Перезапуск",
   "Release Version": "Официальная версия",
   "Alpha Version": "Альфа-версия",
-  "Tun mode requires": "Требуется Режим туннеля",
+  "Please Enable Service Mode": "Пожалуйста, сначала установите и включите режим обслуживания",
   "Grant": "Предоставить",
   "Open UWP tool": "Открыть UWP инструмент",
   "Open UWP tool Info": "С Windows 8 приложения UWP (такие как Microsoft Store) ограничены в прямом доступе к сетевым службам локального хоста, и этот инструмент позволяет обойти это ограничение",

+ 1 - 1
src/locales/zh.json

@@ -266,7 +266,7 @@
   "Restart": "重启内核",
   "Release Version": "正式版",
   "Alpha Version": "预览版",
-  "Tun mode requires": "如需启用 Tun 模式需要授权",
+  "Please Enable Service Mode": "请先安装并启用服务模式",
   "Grant": "授权",
   "Open UWP tool": "UWP 工具",
   "Open UWP tool Info": "Windows 8开始限制 UWP 应用(如微软商店)直接访问本地主机的网络服务,使用此工具可绕过该限制",