import { useMemo } from 'react'; import { useControlSystem } from '../controls/index.js'; import AuthPanel from './AuthPanel.jsx'; import AdminPanel from './AdminPanel.jsx'; import KeymapSettings from './KeymapSettings.jsx'; import GamepadMappingSettings from './GamepadMappingSettings.jsx'; import OvercurrentLimiterPanel from './OvercurrentLimiterPanel.jsx'; import Tabs, { Tab, TabList, TabPanel, TabPanels } from './Tabs.jsx'; import SessionSnapshot from './SessionSnapshot.jsx'; import SocketLogPanel from './SocketLogPanel.jsx'; import { useHudMapSetting } from '../hooks/useHudMapSetting.js'; import { useSettingsNamespace } from '../settings/index.js'; import { useSocket } from '../context/SocketContext.jsx'; import { AUDIO_SETTINGS_DEFAULTS } from '../settings/namespaces.js'; const manualTabs = [ { key: 'start', label: 'Start OI' }, { key: 'safe', label: 'Safe' }, { key: 'full', label: 'Full' }, { key: 'passive', label: 'Passive' }, { key: 'dock', label: 'Dock' }, ]; export default function SettingsPanel() { const { state: { roverId }, actions: { sendOiCommand, setSensorStream }, } = useControlSystem(); const canControl = Boolean(roverId); const [hudMapDesktop, setHudMapDesktop] = useHudMapSetting(); const socket = useSocket(); const { value: pageSettings, save: savePageSettings } = useSettingsNamespace('page', { hudMapDesktop: false, connectionTransport: 'websocket', }); const { value: audioSettings, save: saveAudioSettings } = useSettingsNamespace('audio', AUDIO_SETTINGS_DEFAULTS); const connectionTransport = pageSettings?.connectionTransport || 'websocket'; const masterVolume = Number.isFinite(audioSettings?.masterVolume) ? audioSettings.masterVolume : AUDIO_SETTINGS_DEFAULTS.masterVolume; const alertVolume = Number.isFinite(audioSettings?.alertVolume) ? audioSettings.alertVolume : AUDIO_SETTINGS_DEFAULTS.alertVolume; const roverVolume = Number.isFinite(audioSettings?.roverVolume) ? audioSettings.roverVolume : AUDIO_SETTINGS_DEFAULTS.roverVolume; const autoLevelEnabled = typeof audioSettings?.autoLevelEnabled === 'boolean' ? audioSettings.autoLevelEnabled : AUDIO_SETTINGS_DEFAULTS.autoLevelEnabled; const autoLevelMode = audioSettings?.autoLevelMode === 'duck' ? 'duck' : 'compressor'; const sensorButtons = useMemo( () => [ { key: 'start', label: 'Enable stream', enable: true }, { key: 'stop', label: 'Disable stream', enable: false }, ], [], ); const handleSensorToggle = (enable) => { if (!roverId) return; setSensorStream(enable); }; const handleTransportChange = (event) => { const next = event.target.value; savePageSettings((current) => ({ ...(current ?? {}), connectionTransport: next })); if (!socket?.io?.opts) return; socket.io.opts.transports = next === 'polling' ? ['polling'] : ['websocket', 'polling']; socket.disconnect(); socket.connect(); }; const handleAudioRange = (key) => (event) => { const raw = Number(event.target.value); const next = Number.isFinite(raw) ? Math.max(0, Math.min(1, raw)) : 0; saveAudioSettings((current) => ({ ...(current ?? {}), [key]: next })); }; const handleAutoLevelEnabled = (event) => { const checked = Boolean(event.target.checked); saveAudioSettings((current) => ({ ...(current ?? {}), autoLevelEnabled: checked })); }; const handleAutoLevelMode = (event) => { const next = event.target.value === 'duck' ? 'duck' : 'compressor'; saveAudioSettings((current) => ({ ...(current ?? {}), autoLevelMode: next })); }; return ( Keybindings Controller Page settings Admin

HUD

Mobile HUD keeps the map on by default.

Audio

Compressor evens out incoming audio; ducking lowers volume when cleaning motors are active.

Connection

Switching reconnects your session.

Manual OI commands

{manualTabs.map((tab) => ( ))}

Sensor stream

{sensorButtons.map((btn) => ( ))}
{!canControl &&

Assign a rover to toggle streams.

}
); }