fixing the tray customization issue

This commit is contained in:
coolcoala
2025-08-03 11:12:25 +03:00
parent 445eaadac3
commit 01be6ae70a
2 changed files with 107 additions and 85 deletions

View File

@@ -36,6 +36,7 @@ import {
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import getSystem from "@/utils/get-system"; import getSystem from "@/utils/get-system";
import { Loader2 } from "lucide-react";
const OS = getSystem(); const OS = getSystem();
@@ -69,6 +70,9 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { verge, patchVerge, mutateVerge } = useVerge(); const { verge, patchVerge, mutateVerge } = useVerge();
const [localConfig, setLocalConfig] = useState<Partial<IVergeConfig>>({});
const [loading, setLoading] = useState(false);
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [commonIcon, setCommonIcon] = useState(""); const [commonIcon, setCommonIcon] = useState("");
const [sysproxyIcon, setSysproxyIcon] = useState(""); const [sysproxyIcon, setSysproxyIcon] = useState("");
@@ -96,28 +100,26 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
}, []); }, []);
useEffect(() => { useEffect(() => {
if (open) initIconPath(); if (open) {
}, [open, initIconPath]); setLocalConfig(verge ?? {});
initIconPath();
}
}, [open, verge, initIconPath]);
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
open: () => setOpen(true), open: () => setOpen(true),
close: () => setOpen(false), close: () => setOpen(false),
})); }));
const onSwitchFormat = (_e: any, value: boolean) => value; const handleConfigChange = (patch: Partial<IVergeConfig>) => {
const onError = (err: any) => { setLocalConfig(prev => ({ ...prev, ...patch }));
showNotice("error", err.message || err.toString());
};
const onChangeData = (patch: Partial<IVergeConfig>) => {
mutateVerge({ ...verge, ...patch }, false);
}; };
const handleIconChange = useLockFn( const handleIconChange = useLockFn(
async (type: "common" | "sysproxy" | "tun") => { async (type: "common" | "sysproxy" | "tun") => {
const key = `${type}_tray_icon` as keyof IVergeConfig; const key = `${type}_tray_icon` as keyof IVergeConfig;
if (verge?.[key]) { if (localConfig[key]) {
onChangeData({ [key]: false }); handleConfigChange({ [key]: false });
await patchVerge({ [key]: false });
} else { } else {
const selected = await openDialog({ const selected = await openDialog({
directory: false, directory: false,
@@ -128,72 +130,94 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
const path = Array.isArray(selected) ? selected[0] : selected; const path = Array.isArray(selected) ? selected[0] : selected;
await copyIconFile(path, type); await copyIconFile(path, type);
await initIconPath(); await initIconPath();
onChangeData({ [key]: true }); handleConfigChange({ [key]: true });
await patchVerge({ [key]: true });
} }
} }
}, });
);
const handleSave = useLockFn(async () => {
setLoading(true);
try {
await patchVerge(localConfig);
showNotice("success", t("Settings saved successfully"));
setOpen(false);
} catch (err: any) {
showNotice("error", err.message || err.toString());
} finally {
setLoading(false);
}
});
return ( return (
<Dialog open={open} onOpenChange={setOpen}> <Dialog open={open} onOpenChange={setOpen}>
<DialogContent className="sm:max-w-md"> <DialogContent className="sm:max-w-md">
<DialogHeader> <DialogHeader>
<DialogTitle>{t("Layout Setting")}</DialogTitle> <DialogTitle>{t("Layout Setting")}</DialogTitle>
</DialogHeader> </DialogHeader>
<div className="py-4 space-y-1"> <div className="py-4 space-y-1">
<SettingRow label={t("Memory Usage")}> {OS === "macos" && (
<GuardState <>
value={verge?.enable_memory_usage ?? true} <SettingRow label={t("Tray Icon")}>
valueProps="checked" <Select
onCatch={onError} onValueChange={(value) => handleConfigChange({ tray_icon: value as any })}
onFormat={onSwitchFormat} value={localConfig.tray_icon ?? "monochrome"}
onChange={(e) => onChangeData({ enable_memory_usage: e })} >
onGuard={(e) => patchVerge({ enable_memory_usage: e })} <SelectTrigger className="w-40 h-8"><SelectValue /></SelectTrigger>
> <SelectContent>
<Switch /> <SelectItem value="monochrome">{t("Monochrome")}</SelectItem>
</GuardState> <SelectItem value="colorful">{t("Colorful")}</SelectItem>
</SettingRow> </SelectContent>
</Select>
</SettingRow>
<SettingRow label={t("Proxy Group Icon")}> <SettingRow label={t("Enable Tray Icon")}>
<GuardState <Switch
value={verge?.enable_group_icon ?? true} checked={localConfig.enable_tray_icon ?? true}
valueProps="checked" onCheckedChange={(checked) => handleConfigChange({ enable_tray_icon: checked })}
onCatch={onError} />
onFormat={onSwitchFormat} </SettingRow>
onChange={(e) => onChangeData({ enable_group_icon: e })} </>
onGuard={(e) => patchVerge({ enable_group_icon: e })} )}
>
<Switch />
</GuardState>
</SettingRow>
<SettingRow <SettingRow label={t("Common Tray Icon")}>
label={t("Hover Jump Navigator")} <Button variant="outline" size="sm" className="h-8" onClick={() => handleIconChange("common")}>
extra={<TooltipIcon tooltip={t("Hover Jump Navigator Info")} />} {localConfig.common_tray_icon && commonIcon && (
> <img src={convertFileSrc(commonIcon)} className="h-5 mr-2" alt="common tray icon" />
<GuardState )}
value={verge?.enable_hover_jump_navigator ?? true} {localConfig.common_tray_icon ? t("Clear") : t("Browse")}
valueProps="checked" </Button>
onCatch={onError} </SettingRow>
onFormat={onSwitchFormat}
onChange={(e) => onChangeData({ enable_hover_jump_navigator: e })}
onGuard={(e) => patchVerge({ enable_hover_jump_navigator: e })}
>
<Switch />
</GuardState>
</SettingRow>
</div>
<DialogFooter> <SettingRow label={t("System Proxy Tray Icon")}>
<DialogClose asChild> <Button variant="outline" size="sm" className="h-8" onClick={() => handleIconChange("sysproxy")}>
<Button type="button" variant="outline"> {localConfig.sysproxy_tray_icon && sysproxyIcon && (
{t("Close")} <img src={convertFileSrc(sysproxyIcon)} className="h-5 mr-2" alt="system proxy tray icon" />
)}
{localConfig.sysproxy_tray_icon ? t("Clear") : t("Browse")}
</Button>
</SettingRow>
<SettingRow label={t("Tun Tray Icon")}>
<Button variant="outline" size="sm" className="h-8" onClick={() => handleIconChange("tun")}>
{localConfig.tun_tray_icon && tunIcon && (
<img src={convertFileSrc(tunIcon)} className="h-5 mr-2" alt="tun mode tray icon" />
)}
{localConfig.tun_tray_icon ? t("Clear") : t("Browse")}
</Button>
</SettingRow>
</div>
<DialogFooter>
<DialogClose asChild>
<Button type="button" variant="outline">{t("Cancel")}</Button>
</DialogClose>
<Button type="button" onClick={handleSave} disabled={loading}>
{loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
{t("Save")}
</Button> </Button>
</DialogClose> </DialogFooter>
</DialogFooter> </DialogContent>
</DialogContent> </Dialog>
</Dialog>
); );
}); });

View File

@@ -188,24 +188,22 @@ const SettingVergeBasic = ({ onError }: Props) => {
{OS !== "linux" && ( {OS !== "linux" && (
<SettingRow <SettingRow
label={ label={
<LabelWithIcon <LabelWithIcon
icon={MousePointerClick} icon={MousePointerClick}
text={t("Tray Click Event")} text={t("Tray Click Event")}
/> />
} }
> >
<GuardState <GuardState
value={tray_event ?? "main_window"} value={tray_event ?? "main_window"}
onCatch={onError} onCatch={onError}
onFormat={(v) => v} onFormat={(v) => v}
onChange={(e) => onChangeData({ tray_event: e })} onChange={(e) => onChangeData({ tray_event: e })}
onGuard={(e) => patchVerge({ tray_event: e })} onGuard={(e) => patchVerge({ tray_event: e })}
onChangeProps="onValueChange"
> >
<Select <Select>
onValueChange={(value) => onChangeData({ tray_event: value })}
value={tray_event}
>
<SelectTrigger className="w-40 h-8"> <SelectTrigger className="w-40 h-8">
<SelectValue /> <SelectValue />
</SelectTrigger> </SelectTrigger>