提交应用EQ时判断EQ是否启用和删除不生效的问题

This commit is contained in:
allen2fuc
2026-07-06 17:34:01 +08:00
parent ef83c71239
commit d7e4129053
2 changed files with 137 additions and 42 deletions
+1
View File
@@ -171,6 +171,7 @@ export interface PeqFilter {
export interface PeqState {
filters: PeqFilter[];
peqSelect?: number;
peqEnable?: number; // 0: off, 1: on
peq?: Array<{
name: string;
filters?: PeqFilter[] | string;
+136 -42
View File
@@ -8,6 +8,16 @@
============================================================ */
import BottomNav from "@/components/BottomNav";
import ConnectionPlaceholder from "@/components/ConnectionPlaceholder";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { useDevice } from "@/contexts/DeviceContext";
import {
AI_SPLIT_RESTORE_PATH_KEY,
@@ -30,7 +40,6 @@ import {
} from "@/lib/aiApi";
import { buildPeqSvgCurveData, getFilterType, PeqBandForResponse } from "@/lib/peqAudio";
import { buildPeqPresetBody } from "@/lib/luxsinApi";
import { cn } from "@/lib/utils";
import {
ArrowUp,
@@ -206,12 +215,18 @@ export default function AIPage({ variant = "page", onClose }: AIPageProps = {})
const [routePath, setLocation] = useLocation();
const isLgUp = useIsLgUp();
const { setOpen: setAiPanelOpen } = useAIDrawer();
const { isConnected, deviceState, api } = useDevice();
const { isConnected, deviceState, api, updateSetting } = useDevice();
const mac = deviceState?.mac ?? "";
const language = resolveDeviceLanguage(deviceState?.language);
const deviceName = deviceState?.device ?? "Luxsin X9";
const aiText = useMemo(() => resolveAILocale(language), [language]);
const promptText = useMemo(() => resolveLocalePack(language).prompt, [language]);
const eqUi = useMemo(() => {
const pack = resolveLocalePack(language);
const peq = pack.peq as typeof localeZh.peq;
return peq.eqUi ?? (localeEn.peq as typeof localeEn.peq).eqUi;
}, [language]);
const restoreDesktopSplit = useCallback(() => {
const path = readAndClearAiSplitRestorePath();
@@ -224,6 +239,8 @@ export default function AIPage({ variant = "page", onClose }: AIPageProps = {})
const [input, setInput] = useState("");
const [sending, setSending] = useState(false);
const [historyOpen, setHistoryOpen] = useState(false);
const [pendingDeleteId, setPendingDeleteId] = useState<string | null>(null);
const [pendingApplyMsg, setPendingApplyMsg] = useState<OptimizeUIMessage | null>(null);
const [chats, setChats] = useState<ChatRead[]>([]);
// 初次加载历史会话期间,避免先闪一下欢迎页再切到消息
const [initializing, setInitializing] = useState(true);
@@ -383,27 +400,22 @@ export default function AIPage({ variant = "page", onClose }: AIPageProps = {})
}
}, [aiText, chatId, newChat]);
// ── 历史面板里删除某条会话 ──
const deleteChatById = useCallback(
async (id: string) => {
const ok = window.confirm(aiText.history.deleteConfirm);
if (!ok) return;
try {
await clearChat(id);
setChats((prev) => prev.filter((c) => c.id !== id));
if (chatId === id) {
setChatId(null);
setMessages([]);
}
toast.success(aiText.history.deleted);
} catch (e: any) {
toast.error(
formatText(aiText.history.deleteFailed, { message: e?.message ?? e }),
);
// ── 历史面板里删除某条会话(确认框用 AlertDialogWebView 不支持 window.confirm ──
const confirmDeleteChat = useCallback(async (id: string) => {
try {
await clearChat(id);
setChats((prev) => prev.filter((c) => c.id !== id));
if (chatId === id) {
setChatId(null);
setMessages([]);
}
},
[aiText, chatId],
);
toast.success(aiText.history.deleted);
} catch (e: any) {
toast.error(
formatText(aiText.history.deleteFailed, { message: e?.message ?? e }),
);
}
}, [aiText, chatId]);
// ── 发送提问 ──
const send = useCallback(
@@ -621,8 +633,6 @@ export default function AIPage({ variant = "page", onClose }: AIPageProps = {})
autoPre: selected?.autoPre,
brand: selected?.brand,
model: selected?.model,
target: selected?.target,
form: selected?.form,
filters: (selectedFilters ?? peqState.filters ?? []) as OptimizePeqPayload["filters"],
});
} catch {
@@ -634,7 +644,7 @@ export default function AIPage({ variant = "page", onClose }: AIPageProps = {})
if (isConnected) void refreshCurrentDevicePeq();
}, [isConnected, refreshCurrentDevicePeq]);
const handleApplyToggle = useCallback(
const executeApplyToggle = useCallback(
async (msg: OptimizeUIMessage) => {
if (!api) {
toast.error(aiText.deviceDisconnected);
@@ -642,28 +652,21 @@ export default function AIPage({ variant = "page", onClose }: AIPageProps = {})
}
const nextApplied = !msg.applied;
const targetPeq = nextApplied ? msg.afterPeq : msg.beforePeq;
const metaSource = currentDevicePeq ?? targetPeq;
setApplyingId(msg.id);
try {
await api.upgradePeqChange({
peqChange: buildPeqPresetBody(
{
name: targetPeq.name ?? msg.name ?? metaSource?.name ?? "",
brand: targetPeq.brand ?? metaSource?.brand,
model: targetPeq.model ?? metaSource?.model,
target: targetPeq.target ?? metaSource?.target,
form: targetPeq.form ?? metaSource?.form,
autoPre: targetPeq.autoPre ?? metaSource?.autoPre,
preamp: targetPeq.preamp ?? metaSource?.preamp,
canDel: targetPeq.canDel ?? metaSource?.canDel,
},
(targetPeq.filters ?? []).map((f) => ({
peqChange: {
name: targetPeq.name ?? msg.name,
filters: (targetPeq.filters ?? []).map((f) => ({
type: getFilterType(f.type),
fc: (f.fc ?? f.frequency ?? 1000) as number,
gain: f.gain,
q: f.q,
})),
),
autoPre: targetPeq.autoPre,
preamp: targetPeq.preamp,
canDel: targetPeq.canDel,
},
});
await updateMessageApplied(msg.id, nextApplied);
await api.refreshState();
@@ -687,7 +690,35 @@ export default function AIPage({ variant = "page", onClose }: AIPageProps = {})
setApplyingId(null);
}
},
[aiText, api, currentDevicePeq, refreshCurrentDevicePeq],
[aiText, api, refreshCurrentDevicePeq],
);
const handleApplyToggle = useCallback(
(msg: OptimizeUIMessage) => {
if (!api) {
toast.error(aiText.deviceDisconnected);
return;
}
if ((deviceState?.peqEnable ?? 0) !== 1) {
setPendingApplyMsg(msg);
return;
}
void executeApplyToggle(msg);
},
[aiText, api, deviceState?.peqEnable, executeApplyToggle],
);
const confirmEnableAndApply = useCallback(
async (msg: OptimizeUIMessage) => {
try {
const bypassOn = (deviceState?.dsp_enable ?? 0) === 0;
await updateSetting(bypassOn ? { peqEnable: 1, dsp_enable: 1 } : { peqEnable: 1 });
await executeApplyToggle(msg);
} catch (e: any) {
toast.error(formatText(aiText.optimize.applyFailed, { message: e?.message ?? e }));
}
},
[aiText, deviceState?.dsp_enable, executeApplyToggle, updateSetting],
);
const openCompare = useCallback(
@@ -907,10 +938,72 @@ export default function AIPage({ variant = "page", onClose }: AIPageProps = {})
onClose={() => setHistoryOpen(false)}
onSelect={(id) => loadChat(id)}
onNew={newChat}
onDelete={deleteChatById}
onDelete={setPendingDeleteId}
/>
)}
<AlertDialog
open={pendingDeleteId !== null}
onOpenChange={(open) => {
if (!open) setPendingDeleteId(null);
}}
>
<AlertDialogContent className="top-[42%] z-[70] border-white/10 bg-zinc-900 text-white sm:max-w-md">
<AlertDialogHeader>
<AlertDialogTitle className="text-white">
{aiText.history.delete}
</AlertDialogTitle>
<AlertDialogDescription className="text-white/60">
{aiText.history.deleteConfirm}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel className="border-white/20 bg-transparent text-white hover:bg-white/10">
{promptText.cancel}
</AlertDialogCancel>
<AlertDialogAction
className="bg-red-500 text-white hover:bg-red-500/90 focus-visible:ring-red-500"
onClick={() => {
if (pendingDeleteId) void confirmDeleteChat(pendingDeleteId);
}}
>
{promptText.delete}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<AlertDialog
open={pendingApplyMsg !== null}
onOpenChange={(open) => {
if (!open) setPendingApplyMsg(null);
}}
>
<AlertDialogContent className="top-[42%] z-[70] border-white/10 bg-zinc-900 text-white sm:max-w-md">
<AlertDialogHeader>
<AlertDialogTitle className="text-white">
{eqUi.enableConfirmTitle}
</AlertDialogTitle>
<AlertDialogDescription className="text-white/60">
{eqUi.enableConfirmDesc}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel className="border-white/20 bg-transparent text-white hover:bg-white/10">
{eqUi.cancel}
</AlertDialogCancel>
<AlertDialogAction
className="bg-[#00FFF6] text-black hover:bg-[#00FFF6]/90 focus-visible:ring-[#00FFF6]"
onClick={() => {
if (pendingApplyMsg) void confirmEnableAndApply(pendingApplyMsg);
}}
>
{eqUi.enableConfirmOk}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
{/* ── 对比对话框 ── */}
{compareMsg && (
<CompareDialog
@@ -1157,11 +1250,12 @@ function HistoryPanel({
</span>
)}
<button
type="button"
onClick={(e) => {
e.stopPropagation();
onDelete(c.id);
}}
className="ml-2 w-8 h-8 rounded-full flex items-center justify-center text-white/40 hover:text-red-400 active:text-red-500 transition-colors"
className="ml-2 w-8 h-8 shrink-0 rounded-full flex items-center justify-center text-white/40 hover:text-red-400 active:text-red-500 transition-colors touch-manipulation"
style={{ background: "rgba(44,44,46,0.6)" }}
aria-label={aiText.history.delete}
>