Browse Source

feat: Add animation for provider update

MystiPanda 1 năm trước cách đây
mục cha
commit
27fe28661c

+ 42 - 13
src/components/proxy/provider-button.tsx

@@ -13,14 +13,19 @@ import {
   Typography,
   Divider,
   LinearProgress,
+  keyframes,
 } from "@mui/material";
 import { RefreshRounded } from "@mui/icons-material";
 import { useTranslation } from "react-i18next";
-import { useLockFn } from "ahooks";
 import { getProxyProviders, proxyProviderUpdate } from "@/services/api";
 import { BaseDialog } from "../base";
 import parseTraffic from "@/utils/parse-traffic";
 
+const round = keyframes`
+  from { transform: rotate(0deg); }
+  to { transform: rotate(360deg); }
+`;
+
 export const ProviderButton = () => {
   const { t } = useTranslation();
   const { data } = useSWR("getProxyProviders", getProxyProviders);
@@ -28,12 +33,31 @@ export const ProviderButton = () => {
   const [open, setOpen] = useState(false);
 
   const hasProvider = Object.keys(data || {}).length > 0;
+  const [updating, setUpdating] = useState(
+    Object.keys(data || {}).map(() => false)
+  );
 
-  const handleUpdate = useLockFn(async (key: string) => {
-    await proxyProviderUpdate(key);
-    await mutate("getProxies");
-    await mutate("getProxyProviders");
-  });
+  const setUpdatingAt = (status: boolean, index: number) => {
+    setUpdating((prev) => {
+      const next = [...prev];
+      next[index] = status;
+      return next;
+    });
+  };
+  const handleUpdate = async (key: string, index: number) => {
+    setUpdatingAt(true, index);
+    proxyProviderUpdate(key)
+      .then(async () => {
+        setUpdatingAt(false, index);
+        await mutate("getProxies");
+        await mutate("getProxyProviders");
+      })
+      .catch(async () => {
+        setUpdatingAt(false, index);
+        await mutate("getProxies");
+        await mutate("getProxyProviders");
+      });
+  };
 
   if (!hasProvider) return null;
 
@@ -57,11 +81,11 @@ export const ProviderButton = () => {
               variant="contained"
               size="small"
               onClick={async () => {
-                Object.entries(data || {}).forEach(async ([key, item]) => {
-                  await proxyProviderUpdate(key);
-                  await mutate("getProxies");
-                  await mutate("getProxyProviders");
-                });
+                Object.entries(data || {}).forEach(
+                  async ([key, item], index) => {
+                    await handleUpdate(key, index);
+                  }
+                );
               }}
             >
               {t("Update All")}
@@ -75,7 +99,7 @@ export const ProviderButton = () => {
         onCancel={() => setOpen(false)}
       >
         <List sx={{ py: 0, minHeight: 250 }}>
-          {Object.entries(data || {}).map(([key, item]) => {
+          {Object.entries(data || {}).map(([key, item], index) => {
             const time = dayjs(item.updatedAt);
             const sub = item.subscriptionInfo;
             const hasSubInfo = !!sub;
@@ -149,7 +173,12 @@ export const ProviderButton = () => {
                     size="small"
                     color="inherit"
                     title="Update Provider"
-                    onClick={() => handleUpdate(key)}
+                    onClick={() => handleUpdate(key, index)}
+                    sx={{
+                      animation: updating[index]
+                        ? `1s linear infinite ${round}`
+                        : "none",
+                    }}
                   >
                     <RefreshRounded />
                   </IconButton>

+ 42 - 13
src/components/rule/provider-button.tsx

@@ -12,13 +12,18 @@ import {
   Box,
   alpha,
   Divider,
+  keyframes,
 } from "@mui/material";
 import { RefreshRounded } from "@mui/icons-material";
 import { useTranslation } from "react-i18next";
-import { useLockFn } from "ahooks";
 import { getRuleProviders, ruleProviderUpdate } from "@/services/api";
 import { BaseDialog } from "../base";
 
+const round = keyframes`
+  from { transform: rotate(0deg); }
+  to { transform: rotate(360deg); }
+`;
+
 export const ProviderButton = () => {
   const { t } = useTranslation();
   const { data } = useSWR("getRuleProviders", getRuleProviders);
@@ -26,12 +31,31 @@ export const ProviderButton = () => {
   const [open, setOpen] = useState(false);
 
   const hasProvider = Object.keys(data || {}).length > 0;
+  const [updating, setUpdating] = useState(
+    Object.keys(data || {}).map(() => false)
+  );
 
-  const handleUpdate = useLockFn(async (key: string) => {
-    await ruleProviderUpdate(key);
-    await mutate("getRules");
-    await mutate("getRuleProviders");
-  });
+  const setUpdatingAt = (status: boolean, index: number) => {
+    setUpdating((prev) => {
+      const next = [...prev];
+      next[index] = status;
+      return next;
+    });
+  };
+  const handleUpdate = async (key: string, index: number) => {
+    setUpdatingAt(true, index);
+    ruleProviderUpdate(key)
+      .then(async () => {
+        setUpdatingAt(false, index);
+        await mutate("getRules");
+        await mutate("getRuleProviders");
+      })
+      .catch(async () => {
+        setUpdatingAt(false, index);
+        await mutate("getRules");
+        await mutate("getRuleProviders");
+      });
+  };
 
   if (!hasProvider) return null;
 
@@ -55,11 +79,11 @@ export const ProviderButton = () => {
               variant="contained"
               size="small"
               onClick={async () => {
-                Object.entries(data || {}).forEach(async ([key, item]) => {
-                  await ruleProviderUpdate(key);
-                  await mutate("getRules");
-                  await mutate("getRuleProviders");
-                });
+                Object.entries(data || {}).forEach(
+                  async ([key, item], index) => {
+                    await handleUpdate(key, index);
+                  }
+                );
               }}
             >
               {t("Update All")}
@@ -73,7 +97,7 @@ export const ProviderButton = () => {
         onCancel={() => setOpen(false)}
       >
         <List sx={{ py: 0, minHeight: 250 }}>
-          {Object.entries(data || {}).map(([key, item]) => {
+          {Object.entries(data || {}).map(([key, item], index) => {
             const time = dayjs(item.updatedAt);
             return (
               <>
@@ -122,7 +146,12 @@ export const ProviderButton = () => {
                     size="small"
                     color="inherit"
                     title="Update Provider"
-                    onClick={() => handleUpdate(key)}
+                    onClick={() => handleUpdate(key, index)}
+                    sx={{
+                      animation: updating[index]
+                        ? `1s linear infinite ${round}`
+                        : "none",
+                    }}
                   >
                     <RefreshRounded />
                   </IconButton>

+ 1 - 1
src/components/setting/mods/controller-viewer.tsx

@@ -36,7 +36,7 @@ export const ControllerViewer = forwardRef<DialogRef>((props, ref) => {
   return (
     <BaseDialog
       open={open}
-      title={t("Clash Port")}
+      title={t("External Controller")}
       contentSx={{ width: 400 }}
       okBtn={t("Save")}
       cancelBtn={t("Cancel")}