mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 09:31:20 -04:00
big loud turn indicators
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useSession } from '../context/SessionContext.jsx';
|
||||
import { useTelemetryFrame } from '../context/TelemetryContext.jsx';
|
||||
import { useVideoRequests } from '../hooks/useVideoRequests.js';
|
||||
@@ -9,9 +9,12 @@ import VideoTile from './VideoTile.jsx';
|
||||
export default function DriverVideoPanel({layoutFormat = 'desktop'}) {
|
||||
const { session } = useSession();
|
||||
const {
|
||||
state: { song },
|
||||
state: { song, lastControlIntentAt },
|
||||
} = useControlSystem();
|
||||
const [now, setNow] = useState(() => Date.now());
|
||||
const [turnCueVisible, setTurnCueVisible] = useState(false);
|
||||
const [turnCueStartAt, setTurnCueStartAt] = useState(null);
|
||||
const lastTurnRef = useRef({ active: false, roverId: null });
|
||||
useEffect(() => {
|
||||
if (session?.mode !== 'turns') {
|
||||
return undefined;
|
||||
@@ -38,10 +41,25 @@ export default function DriverVideoPanel({layoutFormat = 'desktop'}) {
|
||||
}, [turnInfo?.queue, turnInfo?.current]);
|
||||
const isNextDriver = Boolean(socketId && nextDriverId === socketId);
|
||||
const deadline = turnInfo?.deadline || null;
|
||||
const idleDeadline = turnInfo?.idleDeadline || null;
|
||||
const msUntilTurn = deadline ? deadline - now : null;
|
||||
const msUntilIdleSkip = idleDeadline ? idleDeadline - now : null;
|
||||
const isPreSwitchWindow =
|
||||
session?.mode === 'turns' && isNextDriver && msUntilTurn != null && msUntilTurn <= 5000 && msUntilTurn > 0;
|
||||
const shouldShowVideo = session?.mode !== 'turns' || isActiveDriver || isPreSwitchWindow;
|
||||
const turnSeconds =
|
||||
msUntilTurn != null && Number.isFinite(msUntilTurn) ? Math.max(0, Math.ceil(msUntilTurn / 1000)) : null;
|
||||
const idleSkipSeconds =
|
||||
msUntilIdleSkip != null && Number.isFinite(msUntilIdleSkip)
|
||||
? Math.max(0, Math.ceil(msUntilIdleSkip / 1000))
|
||||
: null;
|
||||
const turnTimerText = isActiveDriver
|
||||
? turnSeconds != null
|
||||
? `${turnSeconds}s left`
|
||||
: null
|
||||
: isNextDriver && turnSeconds != null
|
||||
? `Your turn in ${turnSeconds}s`
|
||||
: null;
|
||||
const entries = roverId
|
||||
? [
|
||||
...(shouldShowVideo ? [{ type: 'rover', id: roverId, key: roverId }] : []),
|
||||
@@ -65,6 +83,33 @@ export default function DriverVideoPanel({layoutFormat = 'desktop'}) {
|
||||
|
||||
const roverLabel = batteryRecord?.name || (roverId ? `Rover ${roverId}` : '');
|
||||
|
||||
useEffect(() => {
|
||||
if (session?.mode !== 'turns') {
|
||||
setTurnCueVisible(false);
|
||||
setTurnCueStartAt(null);
|
||||
lastTurnRef.current = { active: false, roverId: null };
|
||||
return;
|
||||
}
|
||||
const lastTurn = lastTurnRef.current;
|
||||
const becameActive = isActiveDriver && !lastTurn.active;
|
||||
const roverChanged = isActiveDriver && roverId && roverId !== lastTurn.roverId;
|
||||
if (becameActive || roverChanged) {
|
||||
setTurnCueVisible(true);
|
||||
setTurnCueStartAt(Date.now());
|
||||
} else if (!isActiveDriver && lastTurn.active) {
|
||||
setTurnCueVisible(false);
|
||||
setTurnCueStartAt(null);
|
||||
}
|
||||
lastTurnRef.current = { active: isActiveDriver, roverId };
|
||||
}, [isActiveDriver, roverId, session?.mode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!turnCueVisible || !turnCueStartAt) return;
|
||||
if (lastControlIntentAt > turnCueStartAt) {
|
||||
setTurnCueVisible(false);
|
||||
}
|
||||
}, [lastControlIntentAt, turnCueStartAt, turnCueVisible]);
|
||||
|
||||
return (
|
||||
<section className="panel">
|
||||
{roverId ? (
|
||||
@@ -79,6 +124,11 @@ export default function DriverVideoPanel({layoutFormat = 'desktop'}) {
|
||||
layoutFormat={layoutFormat}
|
||||
songNote={song?.note}
|
||||
qualityNotice={!shouldShowVideo ? 'Preview feed (low FPS) until your turn.' : null}
|
||||
showTurnCue={turnCueVisible}
|
||||
turnTimerText={turnTimerText}
|
||||
turnSeconds={turnSeconds}
|
||||
isActiveDriver={isActiveDriver}
|
||||
idleSkipSeconds={idleSkipSeconds}
|
||||
/>
|
||||
) : (
|
||||
<div className="panel-muted content-center text-center text-sm text-slate-400 aspect-video">
|
||||
|
||||
Reference in New Issue
Block a user