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', swapMobileControlColumns: false, }); const { value: audioSettings, save: saveAudioSettings } = useSettingsNamespace('audio', AUDIO_SETTINGS_DEFAULTS); const connectionTransport = pageSettings?.connectionTransport || 'websocket'; const swapMobileControlColumns = Boolean(pageSettings?.swapMobileControlColumns); 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 mainBrushDuckEnabled = typeof audioSettings?.mainBrushDuckEnabled === 'boolean' ? audioSettings.mainBrushDuckEnabled : typeof audioSettings?.autoLevelEnabled === 'boolean' ? audioSettings.autoLevelEnabled : AUDIO_SETTINGS_DEFAULTS.mainBrushDuckEnabled; const mainBrushDuckAmount = Number.isFinite(audioSettings?.mainBrushDuckAmount) ? Math.max(0, Math.min(1, audioSettings.mainBrushDuckAmount)) : AUDIO_SETTINGS_DEFAULTS.mainBrushDuckAmount; 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 handleMainBrushDuckEnabled = (event) => { const checked = Boolean(event.target.checked); saveAudioSettings((current) => ({ ...(current ?? {}), mainBrushDuckEnabled: checked })); }; const handleSwapMobileControlColumns = (event) => { const checked = Boolean(event.target.checked); savePageSettings((current) => ({ ...(current ?? {}), swapMobileControlColumns: checked })); }; return ( Keybindings Controller Page settings Admin

HUD

Mobile HUD keeps the map on by default.

Mobile controls

Audio

Lowers rover audio only while the main brush is running.

Connection

Switching reconnects your session.

Manual OI commands

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

Sensor stream

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

Assign a rover to toggle streams.

}
); }