Refactor Vite configuration for improved chunking strategy and caching. Enhance DeviceContext with new upgradePeqChange method for PEQ updates. Update audio page to support localized labels and dynamic volume control. Introduce new filter types and improve EQPage functionality with enhanced frequency response visualization.
This commit is contained in:
@@ -13,6 +13,9 @@ import { useLocation } from "wouter";
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import BottomNav from "@/components/BottomNav";
|
||||
import { navigateToSelect } from "./SelectPage";
|
||||
import localeZh from "@/locales/data-zh.json";
|
||||
import localeZhHK from "@/locales/data-zh-HK.json";
|
||||
import localeEn from "@/locales/data-en.json";
|
||||
|
||||
function CyanSlider({ value, min, max, step = 1, onChange }: {
|
||||
value: number; min: number; max: number; step?: number; onChange: (v: number) => void;
|
||||
@@ -47,18 +50,42 @@ function ListRow({ label, value, onClick }: { label: string; value: string; onCl
|
||||
);
|
||||
}
|
||||
|
||||
const FILTER_OPTIONS = ["短延迟快速滚降", "短延迟慢速滚降", "快速滚降", "慢速滚降", "超慢速滚降"];
|
||||
const GAIN_OPTIONS = ["低", "中", "高"];
|
||||
const STEP_OPTIONS = ["0.5dB", "1dB", "2dB"];
|
||||
const XLR_OPTIONS = ["正常", "反转"];
|
||||
const DAC_GAIN_OPTIONS = ["0dB", "+3dB", "+6dB"];
|
||||
const DAC_IMP_OPTIONS = ["32Ω", "150Ω", "300Ω"];
|
||||
type LocaleDac = {
|
||||
dac?: {
|
||||
balance?: string;
|
||||
sensitivity?: string;
|
||||
filters?: { label?: string; options?: Array<{ index: number; label: string }> };
|
||||
dacGain?: { label?: string; options?: Array<{ index: number; label: string }> };
|
||||
volumeStep?: string;
|
||||
xlr?: { label?: string; options?: Array<{ index: number; label: string }> };
|
||||
mutePolar?: { label?: string; options?: Array<{ index: number; label: string }> };
|
||||
IISMode?: { label?: string; options?: Array<{ index: number; label: string }> };
|
||||
};
|
||||
home?: { audioSet?: string };
|
||||
};
|
||||
|
||||
const LOCALE_BY_LANG: Record<number, LocaleDac> = {
|
||||
0: localeEn as LocaleDac,
|
||||
1: localeZhHK as LocaleDac,
|
||||
2: localeZh as LocaleDac,
|
||||
};
|
||||
|
||||
function optionLabels(items: Array<{ index: number; label: string }> | undefined, fallback: string[]) {
|
||||
if (!items || items.length === 0) return fallback;
|
||||
const sorted = [...items].sort((a, b) => a.index - b.index);
|
||||
return sorted.map((item) => item.label);
|
||||
}
|
||||
|
||||
const STEP_OPTIONS = ["0.5dB", "1dB", "2dB", "3dB"];
|
||||
|
||||
export default function AudioPage() {
|
||||
const [, setLocation] = useLocation();
|
||||
const { deviceState, updateSetting } = useDevice();
|
||||
const { deviceState, updateSetting, refresh, isConnected, api } = useDevice();
|
||||
const ds = deviceState;
|
||||
const vuSensor = (ds as ({ vuSensor?: number } | null))?.vuSensor;
|
||||
const langIdx = ds?.language ?? 2;
|
||||
const localeData = LOCALE_BY_LANG[langIdx] ?? (localeZh as LocaleDac);
|
||||
const dacText = localeData.dac ?? {};
|
||||
|
||||
// balance 从接口获取的是乘以 10 后的值,需要除以 10 显示(例如:-130 → -13.0)
|
||||
const balanceVal = ds?.balance !== undefined ? ds.balance / 10 : 0;
|
||||
@@ -66,18 +93,30 @@ export default function AudioPage() {
|
||||
const vuSensVal = vuSensor !== undefined ? vuSensor / 2 : 0;
|
||||
const [localBalance, setLocalBalance] = useState(balanceVal);
|
||||
const [localVuSens, setLocalVuSens] = useState(0);
|
||||
const [filterIdx] = useState(0);
|
||||
const isBalanceDragging = useRef(false);
|
||||
const isVuDragging = useRef(false);
|
||||
|
||||
useEffect(() => { if (!isBalanceDragging.current) setLocalBalance(balanceVal); }, [balanceVal]);
|
||||
useEffect(() => { if (!isVuDragging.current) setLocalVuSens(vuSensVal); }, [vuSensVal]);
|
||||
useEffect(() => {
|
||||
// Ensure we have the latest pcm value from syncData when entering this page
|
||||
if (isConnected || api) {
|
||||
refresh();
|
||||
}
|
||||
}, [isConnected, api, refresh]);
|
||||
|
||||
const gainIdx = ds?.analogGain ?? 0;
|
||||
const gainIdx = ds?.dacGain ?? 0;
|
||||
const stepIdx = ds?.soundStep ?? 1;
|
||||
const filterIdx = ds?.pcm ?? 0;
|
||||
const xlrIdx = ds?.xlr ?? 0;
|
||||
const dacGainIdx = ds?.dacGain ?? 0;
|
||||
const dacImpIdx = ds?.dacImpedance ?? 0;
|
||||
const mutePolarIdx = (ds as ({ hdmimutepolar?: number } | null))?.hdmimutepolar ?? 0;
|
||||
const iisModeIdx = (ds as ({ hdmiType?: number } | null))?.hdmiType ?? 0;
|
||||
|
||||
const FILTER_OPTIONS = optionLabels(dacText.filters?.options, ["快速滚降", "慢速滚降", "短延迟快速滚降", "短延迟慢速滚降", "去重强调", "非过采样(NOS)"]);
|
||||
const GAIN_OPTIONS = optionLabels(dacText.dacGain?.options, ["低", "中", "高"]);
|
||||
const XLR_OPTIONS = optionLabels(dacText.xlr?.options, ["正常", "反转"]);
|
||||
const MUTE_POLAR_OPTIONS = optionLabels(dacText.mutePolar?.options, ["低电平", "高电平"]);
|
||||
const IIS_MODE_OPTIONS = optionLabels(dacText.IISMode?.options, ["模式1", "模式2", "模式3", "模式4", "模式5", "模式6", "模式7", "模式8"]);
|
||||
|
||||
const goSelect = (title: string, options: string[], selected: number, key: string) => {
|
||||
navigateToSelect(title, options, selected, "/audio", key);
|
||||
@@ -90,7 +129,9 @@ export default function AudioPage() {
|
||||
<button onClick={() => setLocation("/")} className="mr-4 text-white/60 active:text-white transition-colors">
|
||||
<ChevronLeft size={24} />
|
||||
</button>
|
||||
<h1 className="flex-1 text-center text-[17px] font-semibold text-white">音频设置</h1>
|
||||
<h1 className="flex-1 text-center text-[17px] font-semibold text-white">
|
||||
{localeData.home?.audioSet ?? "音频设置"}
|
||||
</h1>
|
||||
<div className="w-8" />
|
||||
</div>
|
||||
|
||||
@@ -100,7 +141,7 @@ export default function AudioPage() {
|
||||
<div className="ios-list-group px-4 py-3 space-y-4">
|
||||
<div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-[16px] text-white">左右平衡</span>
|
||||
<span className="text-[16px] text-white">{dacText.balance ?? "左右平衡"}</span>
|
||||
<span className="text-[16px] font-semibold" style={{ color: "#00FFF6" }}>
|
||||
{localBalance >= 0 ? `+${localBalance.toFixed(1)}` : localBalance.toFixed(1)} dB
|
||||
</span>
|
||||
@@ -117,7 +158,7 @@ export default function AudioPage() {
|
||||
<div className="border-t border-white/[0.06]" />
|
||||
<div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-[16px] text-white">VU 表灵敏度</span>
|
||||
<span className="text-[16px] text-white">{dacText.sensitivity ?? "VU 表灵敏度"}</span>
|
||||
<span className="text-[16px] font-semibold" style={{ color: "#00FFF6" }}>
|
||||
{localVuSens >= 0 ? `+${localVuSens}` : localVuSens} dB
|
||||
</span>
|
||||
@@ -136,23 +177,41 @@ export default function AudioPage() {
|
||||
{/* ── 输出特性 ── */}
|
||||
<SectionHeader title="输出特性" />
|
||||
<div className="ios-list-group">
|
||||
<ListRow label="滤波特性" value={FILTER_OPTIONS[filterIdx]}
|
||||
onClick={() => goSelect("选择滤波特性", FILTER_OPTIONS, filterIdx, "filterCharacteristic")} />
|
||||
<ListRow label="耳机增益" value={GAIN_OPTIONS[gainIdx]}
|
||||
onClick={() => goSelect("选择耳机增益", GAIN_OPTIONS, gainIdx, "analogGain")} />
|
||||
<ListRow label="音量幅度" value={STEP_OPTIONS[stepIdx]}
|
||||
onClick={() => goSelect("选择音量幅度", STEP_OPTIONS, stepIdx, "soundStep")} />
|
||||
<ListRow
|
||||
label={dacText.filters?.label ?? "滤波特性"}
|
||||
value={FILTER_OPTIONS[filterIdx] ?? FILTER_OPTIONS[0] ?? "—"}
|
||||
onClick={() => goSelect(dacText.filters?.label ?? "选择滤波特性", FILTER_OPTIONS, filterIdx, "filterCharacteristic")}
|
||||
/>
|
||||
<ListRow
|
||||
label={dacText.dacGain?.label ?? "耳机增益"}
|
||||
value={GAIN_OPTIONS[gainIdx] ?? GAIN_OPTIONS[0] ?? "—"}
|
||||
onClick={() => goSelect(dacText.dacGain?.label ?? "选择耳机增益", GAIN_OPTIONS, gainIdx, "dacGain")}
|
||||
/>
|
||||
<ListRow
|
||||
label={dacText.volumeStep ?? "音量幅度"}
|
||||
value={STEP_OPTIONS[stepIdx] ?? STEP_OPTIONS[0]}
|
||||
onClick={() => goSelect(dacText.volumeStep ?? "选择音量幅度", STEP_OPTIONS, stepIdx, "soundStep")}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* ── 系统与接口 ── */}
|
||||
<SectionHeader title="系统与接口" />
|
||||
<div className="ios-list-group">
|
||||
<ListRow label="XLR 端口极性" value={XLR_OPTIONS[xlrIdx]}
|
||||
onClick={() => goSelect("选择 XLR 极性", XLR_OPTIONS, xlrIdx, "xlr")} />
|
||||
<ListRow label="DAC 增益" value={DAC_GAIN_OPTIONS[dacGainIdx]}
|
||||
onClick={() => goSelect("选择 DAC 增益", DAC_GAIN_OPTIONS, dacGainIdx, "dacGain")} />
|
||||
<ListRow label="DAC 阻抗" value={DAC_IMP_OPTIONS[dacImpIdx]}
|
||||
onClick={() => goSelect("选择 DAC 阻抗", DAC_IMP_OPTIONS, dacImpIdx, "dacImpedance")} />
|
||||
<ListRow
|
||||
label={dacText.xlr?.label ?? "XLR 端口极性"}
|
||||
value={XLR_OPTIONS[xlrIdx] ?? XLR_OPTIONS[0] ?? "—"}
|
||||
onClick={() => goSelect(dacText.xlr?.label ?? "选择 XLR 极性", XLR_OPTIONS, xlrIdx, "xlr")}
|
||||
/>
|
||||
<ListRow
|
||||
label={dacText.mutePolar?.label ?? "IIS 静音电平"}
|
||||
value={MUTE_POLAR_OPTIONS[mutePolarIdx] ?? MUTE_POLAR_OPTIONS[0] ?? "—"}
|
||||
onClick={() => goSelect(dacText.mutePolar?.label ?? "选择 IIS 静音电平", MUTE_POLAR_OPTIONS, mutePolarIdx, "mutePolar")}
|
||||
/>
|
||||
<ListRow
|
||||
label={dacText.IISMode?.label ?? "IIS 模式"}
|
||||
value={IIS_MODE_OPTIONS[iisModeIdx] ?? IIS_MODE_OPTIONS[0] ?? "—"}
|
||||
onClick={() => goSelect(dacText.IISMode?.label ?? "选择 IIS 模式", IIS_MODE_OPTIONS, iisModeIdx, "IISMode")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user