// Movement Column // Purpose: Assembles the mobile movement column, which is the right column by default. // Scope: Owns movement availability while the in-video DockingHud owns every dock/undock action. import { FaChargingStation } from 'react-icons/fa'; import { useControlSelector } from '../../controls/index.js'; import { useSessionSelector } from '../../context/SessionContext.jsx'; import { useTelemetrySelector } from '../../context/TelemetryContext.jsx'; import { dockTelemetryEqual, resolveDocked, selectDockTelemetry } from '../../context/telemetryViews.js'; import { useManualDockAssist } from '../../features/manualDockAssist/useManualDockAssist.js'; import useCanControlRover from '../../hooks/useCanControlRover.js'; import { triggerTouchHaptic } from '../../lib/touchHaptics.js'; import ControlPadPanel from './ControlPadPanel.jsx'; function MovementColumnContent({ layout }) { const roverId = useControlSelector((control) => control.state.roverId); const dockTelemetry = useTelemetrySelector(roverId, selectDockTelemetry, dockTelemetryEqual); const dockAssist = useManualDockAssist(); const canControl = useCanControlRover(roverId); const batteryState = useSessionSelector((state) => { const rover = (state.session?.roster || []).find((entry) => String(entry.id) === String(roverId)); return rover?.batteryState || null; }); const batteryUrgent = Boolean(batteryState?.urgentActive); const batteryLow = Boolean(batteryState?.warnActive || batteryUrgent); const docked = resolveDocked(dockTelemetry); const drivingMode = String(dockTelemetry?.oiModeLabel || '').toLowerCase() === 'full'; /* DockingHud is now the only place where a user starts driving or enters docking assist. This column only decides whether touch movement is safe. Requiring both an undocked rover and full OI mode keeps the pad inert throughout the undock macro, including the interval where dock contact and OI mode change separately. Manual assist is the deliberate exception to the normal OI-mode requirement: its entire purpose is to let the user drive onto the dock under the assist speed cap. Actual dock contact still disables movement immediately. */ const movementDisabled = !roverId || !canControl || docked || (!drivingMode && !dockAssist.active); // Both controls share the same hardware-availability boundary. Dock assist // changes their actions, not who is allowed to command the rover. const dockActionDisabled = movementDisabled; const handleDockAction = () => { if (dockActionDisabled) return; triggerTouchHaptic('button'); // Mobile deliberately enters assist on the first tap. The centered video HUD // provides the resulting instruction, so a confirmation modal would only add // friction between intent and the camera-guided docking task. if (dockAssist.active) { dockAssist.exitAssist(); } else { dockAssist.enterAssist(); } }; return (
{/* Keeping the pad mounted prevents the mobile columns from changing size while the centered video HUD explains and performs dock-related transitions. */}
); } export default function MovementColumn({ layout, className = '' }) { return (
); }