Enhance audio settings: Added loudness controls and headphone model synchronization. Updated PeqState interface to include peq filters. Improved EQPage to dynamically load headphone models based on device state.

This commit is contained in:
yangy
2026-04-01 16:29:52 +08:00
parent 30db710093
commit 502f708336
11 changed files with 181 additions and 74 deletions
+60 -14
View File
@@ -13,7 +13,7 @@
import { useDevice } from "@/contexts/DeviceContext";
import { ChevronLeft, ChevronDown, Minus, Plus, Edit3, Headphones } from "lucide-react";
import { useLocation } from "wouter";
import { useState, useMemo } from "react";
import { useState, useMemo, useEffect } from "react";
import { cn } from "@/lib/utils";
import BottomNav from "@/components/BottomNav";
import { toast } from "sonner";
@@ -47,14 +47,6 @@ function CyanSlider({ value, min, max, step = 1, onChange }: {
/* ── Constants ── */
const FILTER_TYPES = ["PEAK", "LSHELF", "HSHELF", "NOTCH", "LPF", "HPF"];
const HEADPHONE_MODELS = [
"Sennheiser HD 650",
"Sennheiser HD 800",
"Sony WH-1000XM5",
"AKG K701",
"Beyerdynamic DT 990",
"Audio-Technica ATH-M50x",
];
/* ── Frequency Response Chart ── */
function FreqChart({
@@ -211,15 +203,69 @@ function freqLabel(f: number) {
/* ── Main Component ── */
export default function EQPage() {
const [, setLocation] = useLocation();
const { deviceState, updateSetting } = useDevice();
const { deviceState, updateSetting, api, isDemoMode } = useDevice();
const eqOn = (deviceState?.peqEnable ?? 0) === 1;
const [bands, setBands] = useState(DEFAULT_BANDS);
const [selectedBand, setSelectedBand] = useState(3);
const [headphoneIdx, setHeadphoneIdx] = useState(0);
const [headphoneIdx, setHeadphoneIdx] = useState(deviceState?.peqSelect ?? 0);
const [headphoneModels, setHeadphoneModels] = useState<string[]>([]);
const [abMode, setAbMode] = useState<"A" | "B">("A");
const [autoGain, setAutoGain] = useState(false);
// 同步 peqSelect 变化
useEffect(() => {
if (deviceState?.peqSelect !== undefined) {
setHeadphoneIdx(deviceState.peqSelect);
}
}, [deviceState?.peqSelect]);
// 加载耳机列表
useEffect(() => {
async function loadHeadphones() {
if (isDemoMode || !api) {
// 演示模式使用默认列表
setHeadphoneModels([
"Sennheiser HD 650",
"Sennheiser HD 800",
"Sony WH-1000XM5",
"AKG K701",
"Beyerdynamic DT 990",
"Audio-Technica ATH-M50x",
]);
return;
}
try {
const peqState = await api.getPeqState();
if (peqState.peq && peqState.peq.length > 0) {
setHeadphoneModels(peqState.peq.map(h => h.name));
} else {
// 如果没有数据,使用默认列表
setHeadphoneModels([
"Sennheiser HD 650",
"Sennheiser HD 800",
"Sony WH-1000XM5",
"AKG K701",
"Beyerdynamic DT 990",
"Audio-Technica ATH-M50x",
]);
}
} catch (error) {
console.error("Failed to load headphone models:", error);
// 出错时使用默认列表
setHeadphoneModels([
"Sennheiser HD 650",
"Sennheiser HD 800",
"Sony WH-1000XM5",
"AKG K701",
"Beyerdynamic DT 990",
"Audio-Technica ATH-M50x",
]);
}
}
loadHeadphones();
}, [api, isDemoMode]);
const band = bands[selectedBand];
const updateBand = (idx: number, patch: Partial<typeof bands[0]>) => {
@@ -271,10 +317,10 @@ export default function EQPage() {
<button
className="flex items-center gap-2 active:opacity-70 transition-opacity"
onClick={() => {
navigateToSelect("选择耳机型号", HEADPHONE_MODELS, headphoneIdx, "/eq", "headphone");
navigateToSelect("选择耳机型号", headphoneModels, headphoneIdx, "/eq", "headphone");
setLocation("/select");
}}>
<span className="text-[20px] font-bold text-white">{HEADPHONE_MODELS[headphoneIdx]}</span>
<span className="text-[20px] font-bold text-white">{headphoneModels[headphoneIdx]}</span>
<ChevronDown size={18} className="text-white/50" />
</button>
<div className="flex items-center gap-2">
@@ -287,7 +333,7 @@ export default function EQPage() {
<button
className="w-9 h-9 rounded-full flex items-center justify-center text-white/60 active:text-white transition-colors"
style={{ background: "rgba(44,44,46,0.8)", border: "1px solid rgba(255,255,255,0.1)" }}
onClick={() => setHeadphoneIdx((i) => Math.min(HEADPHONE_MODELS.length - 1, i + 1))}>
onClick={() => setHeadphoneIdx((i) => Math.min(headphoneModels.length - 1, i + 1))}>
<Plus size={15} />
</button>
</div>