feat: Add animation for provider update

This commit is contained in:
MystiPanda 2024-03-02 13:52:48 +08:00
parent bb13b12de6
commit 27fe28661c
No known key found for this signature in database
GPG Key ID: 47D0F0284DC57888
3 changed files with 85 additions and 27 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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")}