mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-04-16 23:40:32 +08:00
refactor(icon): extract icon cache logic into reusable hook
This commit is contained in:
parent
f3b9eedcf7
commit
522eccdd0e
@ -9,10 +9,8 @@ import {
|
|||||||
alpha,
|
alpha,
|
||||||
styled,
|
styled,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { convertFileSrc } from "@tauri-apps/api/core";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
|
|
||||||
import { downloadIconCache } from "@/services/cmds";
|
import { useIconCache } from "@/hooks/use-icon-cache";
|
||||||
interface Props {
|
interface Props {
|
||||||
type: "prepend" | "original" | "delete" | "append";
|
type: "prepend" | "original" | "delete" | "append";
|
||||||
group: IProxyGroupConfig;
|
group: IProxyGroupConfig;
|
||||||
@ -38,40 +36,10 @@ export const GroupItem = (props: Props) => {
|
|||||||
const dragListeners = sortable ? sortableListeners : undefined;
|
const dragListeners = sortable ? sortableListeners : undefined;
|
||||||
const dragNodeRef = sortable ? sortableSetNodeRef : undefined;
|
const dragNodeRef = sortable ? sortableSetNodeRef : undefined;
|
||||||
|
|
||||||
const [iconCachePath, setIconCachePath] = useState("");
|
const iconCachePath = useIconCache({
|
||||||
|
icon: group.icon,
|
||||||
useEffect(() => {
|
cacheKey: group.name.replaceAll(" ", ""),
|
||||||
let cancelled = false;
|
});
|
||||||
const initIconCachePath = async () => {
|
|
||||||
const icon = group.icon?.trim() ?? "";
|
|
||||||
if (icon.startsWith("http")) {
|
|
||||||
try {
|
|
||||||
const fileName =
|
|
||||||
group.name.replaceAll(" ", "") + "-" + getFileName(icon);
|
|
||||||
const iconPath = await downloadIconCache(icon, fileName);
|
|
||||||
if (!cancelled) {
|
|
||||||
setIconCachePath(convertFileSrc(iconPath));
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
if (!cancelled) {
|
|
||||||
setIconCachePath("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (!cancelled) {
|
|
||||||
setIconCachePath("");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void initIconCachePath();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
cancelled = true;
|
|
||||||
};
|
|
||||||
}, [group.icon, group.name]);
|
|
||||||
|
|
||||||
function getFileName(url: string) {
|
|
||||||
return url.substring(url.lastIndexOf("/") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItem
|
<ListItem
|
||||||
|
|||||||
@ -13,12 +13,11 @@ import {
|
|||||||
Chip,
|
Chip,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { convertFileSrc } from "@tauri-apps/api/core";
|
import { useMemo } from "react";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
import { useIconCache } from "@/hooks/use-icon-cache";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
import { downloadIconCache } from "@/services/cmds";
|
|
||||||
import { useThemeMode } from "@/services/states";
|
import { useThemeMode } from "@/services/states";
|
||||||
|
|
||||||
import { ProxyHead } from "./proxy-head";
|
import { ProxyHead } from "./proxy-head";
|
||||||
@ -57,26 +56,11 @@ export const ProxyRender = (props: RenderProps) => {
|
|||||||
const mode = useThemeMode();
|
const mode = useThemeMode();
|
||||||
const isDark = mode === "light" ? false : true;
|
const isDark = mode === "light" ? false : true;
|
||||||
const itembackgroundcolor = isDark ? "#282A36" : "#ffffff";
|
const itembackgroundcolor = isDark ? "#282A36" : "#ffffff";
|
||||||
const [iconCachePath, setIconCachePath] = useState("");
|
const iconCachePath = useIconCache({
|
||||||
|
icon: group.icon,
|
||||||
const initIconCachePath = useCallback(async () => {
|
cacheKey: group.name.replaceAll(" ", ""),
|
||||||
if (group.icon && group.icon.trim().startsWith("http")) {
|
enabled: enable_group_icon,
|
||||||
const fileName =
|
});
|
||||||
group.name.replaceAll(" ", "") + "-" + getFileName(group.icon);
|
|
||||||
const iconPath = await downloadIconCache(group.icon, fileName);
|
|
||||||
setIconCachePath(convertFileSrc(iconPath));
|
|
||||||
} else {
|
|
||||||
setIconCachePath("");
|
|
||||||
}
|
|
||||||
}, [group.icon, group.name]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
initIconCachePath();
|
|
||||||
}, [initIconCachePath]);
|
|
||||||
|
|
||||||
function getFileName(url: string) {
|
|
||||||
return url.substring(url.lastIndexOf("/") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const proxyColItemsMemo = useMemo(() => {
|
const proxyColItemsMemo = useMemo(() => {
|
||||||
if (type !== 4 || !proxyCol) {
|
if (type !== 4 || !proxyCol) {
|
||||||
|
|||||||
@ -2,15 +2,15 @@ import { useSortable } from "@dnd-kit/sortable";
|
|||||||
import { CSS } from "@dnd-kit/utilities";
|
import { CSS } from "@dnd-kit/utilities";
|
||||||
import { LanguageRounded } from "@mui/icons-material";
|
import { LanguageRounded } from "@mui/icons-material";
|
||||||
import { Box, Divider, MenuItem, Menu, styled, alpha } from "@mui/material";
|
import { Box, Divider, MenuItem, Menu, styled, alpha } from "@mui/material";
|
||||||
import { convertFileSrc } from "@tauri-apps/api/core";
|
|
||||||
import { UnlistenFn } from "@tauri-apps/api/event";
|
import { UnlistenFn } from "@tauri-apps/api/event";
|
||||||
import { useLockFn } from "ahooks";
|
import { useLockFn } from "ahooks";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { BaseLoading } from "@/components/base";
|
import { BaseLoading } from "@/components/base";
|
||||||
|
import { useIconCache } from "@/hooks/use-icon-cache";
|
||||||
import { useListen } from "@/hooks/use-listen";
|
import { useListen } from "@/hooks/use-listen";
|
||||||
import { cmdTestDelay, downloadIconCache } from "@/services/cmds";
|
import { cmdTestDelay } from "@/services/cmds";
|
||||||
import delayManager from "@/services/delay";
|
import delayManager from "@/services/delay";
|
||||||
import { showNotice } from "@/services/notice-service";
|
import { showNotice } from "@/services/notice-service";
|
||||||
import { debugLog } from "@/utils/debug";
|
import { debugLog } from "@/utils/debug";
|
||||||
@ -46,7 +46,7 @@ export const TestItem = ({
|
|||||||
const [position, setPosition] = useState({ left: 0, top: 0 });
|
const [position, setPosition] = useState({ left: 0, top: 0 });
|
||||||
const [delay, setDelay] = useState(-1);
|
const [delay, setDelay] = useState(-1);
|
||||||
const { uid, name, icon, url } = itemData;
|
const { uid, name, icon, url } = itemData;
|
||||||
const [iconCachePath, setIconCachePath] = useState("");
|
const iconCachePath = useIconCache({ icon, cacheKey: uid });
|
||||||
const { addListener } = useListen();
|
const { addListener } = useListen();
|
||||||
|
|
||||||
const onDelay = useCallback(async () => {
|
const onDelay = useCallback(async () => {
|
||||||
@ -55,24 +55,6 @@ export const TestItem = ({
|
|||||||
setDelay(result);
|
setDelay(result);
|
||||||
}, [url]);
|
}, [url]);
|
||||||
|
|
||||||
const initIconCachePath = useCallback(async () => {
|
|
||||||
if (icon && icon.trim().startsWith("http")) {
|
|
||||||
const fileName = uid + "-" + getFileName(icon);
|
|
||||||
const iconPath = await downloadIconCache(icon, fileName);
|
|
||||||
setIconCachePath(convertFileSrc(iconPath));
|
|
||||||
} else {
|
|
||||||
setIconCachePath("");
|
|
||||||
}
|
|
||||||
}, [icon, uid]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
void initIconCachePath();
|
|
||||||
}, [initIconCachePath]);
|
|
||||||
|
|
||||||
function getFileName(url: string) {
|
|
||||||
return url.substring(url.lastIndexOf("/") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const onEditTest = () => {
|
const onEditTest = () => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
onEdit();
|
onEdit();
|
||||||
|
|||||||
54
src/hooks/use-icon-cache.ts
Normal file
54
src/hooks/use-icon-cache.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { convertFileSrc } from "@tauri-apps/api/core";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import useSWR from "swr";
|
||||||
|
|
||||||
|
import { downloadIconCache } from "@/services/cmds";
|
||||||
|
import { SWR_DEFAULTS } from "@/services/config";
|
||||||
|
|
||||||
|
export interface UseIconCacheOptions {
|
||||||
|
icon?: string | null;
|
||||||
|
cacheKey?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFileNameFromUrl = (url: string) => {
|
||||||
|
const lastSlashIndex = url.lastIndexOf("/");
|
||||||
|
return lastSlashIndex >= 0 ? url.slice(lastSlashIndex + 1) : url;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useIconCache = ({
|
||||||
|
icon,
|
||||||
|
cacheKey,
|
||||||
|
enabled = true,
|
||||||
|
}: UseIconCacheOptions) => {
|
||||||
|
const iconValue = icon?.trim() ?? "";
|
||||||
|
const cacheKeyValue = cacheKey?.trim() ?? "";
|
||||||
|
|
||||||
|
const swrKey = useMemo(() => {
|
||||||
|
if (!enabled || !iconValue.startsWith("http") || cacheKeyValue === "") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ["icon-cache", iconValue, cacheKeyValue] as const;
|
||||||
|
}, [enabled, iconValue, cacheKeyValue]);
|
||||||
|
|
||||||
|
const { data } = useSWR(
|
||||||
|
swrKey,
|
||||||
|
async () => {
|
||||||
|
try {
|
||||||
|
const fileName = `${cacheKeyValue}-${getFileNameFromUrl(iconValue)}`;
|
||||||
|
const iconPath = await downloadIconCache(iconValue, fileName);
|
||||||
|
return convertFileSrc(iconPath);
|
||||||
|
} catch {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SWR_DEFAULTS,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!swrKey) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return data ?? "";
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user