/* ============================================================ SYSTEM PAGE — Settings Design: Reference luxsin_x8_设置.png Sections: - 显示: 屏幕亮度, 自动锁屏, 旋钮亮度, 旋钮熄屏呼吸灯 - 通用: 语言, 自动返回首页, 休眠 - 声音: 开机提示音 - 关于: 设备名, 固件版本, MAC All list rows with options → navigate to /select page ============================================================ */ import { useDevice } from "@/contexts/DeviceContext"; import { ChevronLeft, ChevronRight } from "lucide-react"; import { useLocation } from "wouter"; import { useEffect, useRef, useState } from "react"; import BottomNav from "@/components/BottomNav"; import { navigateToSelect } from "./SelectPage"; import { clampLedChannel, formatFirmwareVersionDisplay, parseFirmwareVersion, supportsAmbientLed, } from "@/lib/luxsinApi"; import localeEn from "@/locales/data-en.json"; import { DEFAULT_DEVICE_LANGUAGE, resolveDeviceLanguage, resolveLocalePack } from "@/locales/resolveLocale"; import { usePageTitleWithConnection } from "@/hooks/usePageTitleWithConnection"; function IOSToggle({ checked, onChange }: { checked: boolean; onChange: (v: boolean) => void }) { return ( ); } function SectionHeader({ title }: { title: string }) { return (
{title}
); } function CyanSlider({ value, min, max, step = 1, onChange, onRelease, }: { value: number; min: number; max: number; step?: number; onChange: (v: number) => void; onRelease?: (v: number) => void; }) { const fillPct = ((value - min) / (max - min)) * 100; const emitRelease = (el: EventTarget | null) => { if (!(el instanceof HTMLInputElement)) return; onRelease?.(Number(el.value)); }; return (
onChange(Number(e.target.value))} onPointerUp={(e) => emitRelease(e.currentTarget)} onPointerCancel={(e) => emitRelease(e.currentTarget)} onKeyUp={(e) => { if ( ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End", "PageUp", "PageDown"].includes( e.key, ) ) { emitRelease(e.currentTarget); } }} />
); } function ListRow({ label, description, value, onClick, toggle, checked, onToggle }: { label: string; description?: string; value?: string; onClick?: () => void; toggle?: boolean; checked?: boolean; onToggle?: (v: boolean) => void; }) { if (toggle) { return (
{label}
{description &&
{description}
}
{})} />
); } return ( ); } type LocaleSettings = { settings: { vu: string; vuMeter?: string; screenBrightness: { label: string; options: Array<{ index: number; label: string }> }; turnOffScreen: { label: string; options: Array<{ index: number; label: string }> }; knobBrightness: { label: string; options: Array<{ index: number; label: string }> }; buttonLight: { label: string; options: Array<{ index: number; label: string }> }; language: { label: string; options: Array<{ index: number; label: string }> }; Automatic: { label: string; options: Array<{ index: number; label: string }> }; sleepTime?: { label: string; options: Array<{ index: number; label: string }> }; sleep?: { label: string; options: Array<{ index: number; label: string }> }; systemPage: { sectionDisplay: string; sectionGeneral: string; sectionAbout: string; screenBrightnessDesc: string; turnOffScreenDesc: string; knobBrightnessDesc: string; buttonLightDesc: string; languageDesc: string; automaticDesc: string; sleepDesc: string; deviceName: string; firmwareVersion: string; macAddress: string; deviceIp: string; sectionAmbientLight?: string; ambientLight?: string; ledRed?: string; ledGreen?: string; ledBlue?: string; }; }; }; 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); } /** Device language index: 0=en, 1=zh-HK, 2=zh-CN */ const SUPPORTED_LANGUAGE_INDICES = new Set([0, 1, 2]); function languageLabels( items: Array<{ index: number; label: string }> | undefined, fallback: string[], ) { const filtered = (items ?? []).filter((o) => SUPPORTED_LANGUAGE_INDICES.has(o.index)); if (filtered.length === 0) return fallback; return [...filtered].sort((a, b) => a.index - b.index).map((o) => o.label); } export default function SystemPage() { const [, setLocation] = useLocation(); const { deviceState, updateSetting, refresh, isConnected, api, ip } = useDevice(); const ds = deviceState; // 页面加载且已连接时刷新数据 useEffect(() => { if (isConnected || api) { refresh(); } }, [isConnected, api]); const screenLightIdx = ds?.screenLight ?? 1; const buttonLightIdx = ds?.buttonLight ?? 1; const screenOffIdx = ds?.screenOff ?? 2; const sleepIdx = ds?.sleep ?? 0; const autoHomeIdx = ds?.autoHome ?? 1; const rawLangIdx = resolveDeviceLanguage(ds?.language); const langIdx = SUPPORTED_LANGUAGE_INDICES.has(rawLangIdx) ? rawLangIdx : DEFAULT_DEVICE_LANGUAGE; const knobBreathLightOn = (ds?.knob_breathlight ?? 1) === 0; const firmwareVersion = parseFirmwareVersion(ds?.version); const showAmbientLed = supportsAmbientLed(firmwareVersion); const ledOn = (ds?.led_enable ?? 0) === 1; const [localLedRed, setLocalLedRed] = useState(() => clampLedChannel(ds?.led_red)); const [localLedGreen, setLocalLedGreen] = useState(() => clampLedChannel(ds?.led_green)); const [localLedBlue, setLocalLedBlue] = useState(() => clampLedChannel(ds?.led_blue)); const draggingLedRed = useRef(false); const draggingLedGreen = useRef(false); const draggingLedBlue = useRef(false); useEffect(() => { if (!draggingLedRed.current) setLocalLedRed(clampLedChannel(ds?.led_red)); }, [ds?.led_red]); useEffect(() => { if (!draggingLedGreen.current) setLocalLedGreen(clampLedChannel(ds?.led_green)); }, [ds?.led_green]); useEffect(() => { if (!draggingLedBlue.current) setLocalLedBlue(clampLedChannel(ds?.led_blue)); }, [ds?.led_blue]); const localeData = resolveLocalePack(ds?.language) as LocaleSettings; const settingsText = localeData.settings; const ui = settingsText.systemPage; const SCREEN_LIGHT_OPTIONS = optionLabels(settingsText.screenBrightness?.options, ["亮", "中等", "暗"]); const KNOB_LIGHT_OPTIONS = optionLabels(settingsText.knobBrightness?.options, ["关闭", "亮", "中等", "暗"]); const SCREEN_OFF_OPTIONS = optionLabels(settingsText.turnOffScreen?.options, ["常亮", "30秒", "1分钟", "3分钟", "5分钟"]); const SLEEP_OPTIONS = optionLabels(settingsText.sleepTime?.options ?? settingsText.sleep?.options, ["关闭", "1分钟", "5分钟", "10分钟"]); const AUTO_HOME_OPTIONS = optionLabels(settingsText.Automatic?.options, ["关闭", "20秒", "40秒", "60秒"]); const LANG_OPTIONS = languageLabels(settingsText.language?.options, [ "English", "繁體中文", "简体中文", ]); const sleepRowLabel = settingsText.sleepTime?.label ?? settingsText.sleep?.label ?? (localeEn as LocaleSettings).settings.sleep?.label ?? "Sleep"; const pageTitle = usePageTitleWithConnection(settingsText.vu); const goSelect = (title: string, options: string[], selected: number, key: string) => { navigateToSelect(title, options, selected, "/system", key); setLocation("/select"); }; return (

{pageTitle}

{/* ── 显示 ── */}
goSelect(settingsText.screenBrightness.label, SCREEN_LIGHT_OPTIONS, screenLightIdx, "screenLight")} /> goSelect(settingsText.turnOffScreen.label, SCREEN_OFF_OPTIONS, screenOffIdx, "screenOff")} /> goSelect(settingsText.knobBrightness.label, KNOB_LIGHT_OPTIONS, buttonLightIdx, "buttonLight")} /> updateSetting({ knob_breathlight: v ? 0 : 1 })} />
{showAmbientLed && ( <>
updateSetting({ led_enable: v ? 1 : 0 })} />
{ledOn && (
{ui.ledRed ?? "红"} {localLedRed}
{ draggingLedRed.current = true; setLocalLedRed(v); }} onRelease={(v) => { draggingLedRed.current = false; updateSetting({ led_red: clampLedChannel(v) }); }} />
{ui.ledGreen ?? "绿"} {localLedGreen}
{ draggingLedGreen.current = true; setLocalLedGreen(v); }} onRelease={(v) => { draggingLedGreen.current = false; updateSetting({ led_green: clampLedChannel(v) }); }} />
{ui.ledBlue ?? "蓝"} {localLedBlue}
{ draggingLedBlue.current = true; setLocalLedBlue(v); }} onRelease={(v) => { draggingLedBlue.current = false; updateSetting({ led_blue: clampLedChannel(v) }); }} />
)}
)} {/* ── 通用 ── */}
goSelect(settingsText.language.label, LANG_OPTIONS, langIdx, "language")} /> goSelect(settingsText.Automatic.label, AUTO_HOME_OPTIONS, autoHomeIdx, "autoHome")} /> goSelect(sleepRowLabel, SLEEP_OPTIONS, sleepIdx, "sleep")} />
{/* ── 关于 ── */}
{ui.deviceName} {ds?.device ?? "Luxsin X9"}
{ui.firmwareVersion} {formatFirmwareVersionDisplay(ds?.version)}
{ui.macAddress} {ds?.mac ?? "—"}
{ui.deviceIp ?? "设备 IP"} {ip || "—"}
); }