This commit is contained in:
legop3
2026-01-30 22:37:39 -05:00
parent ca3d95319d
commit fd06f23de4
4 changed files with 86 additions and 45 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -11,8 +11,8 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" /> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" /> <meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
<title>Multi Roomba Rover</title> <title>Multi Roomba Rover</title>
<script type="module" crossorigin src="/assets/index-f56Apeln.js"></script> <script type="module" crossorigin src="/assets/index-MsCzfGxI.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DMYOk2Xw.css"> <link rel="stylesheet" crossorigin href="/assets/index-C97A4E-6.css">
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
+75 -34
View File
@@ -220,7 +220,9 @@ function MiniSummaryContent() {
const frames = useTelemetryFrames(); const frames = useTelemetryFrames();
const roster = session?.roster ?? []; const roster = session?.roster ?? [];
const [index, setIndex] = useState(0); const [index, setIndex] = useState(0);
const [prewarmRoverId, setPrewarmRoverId] = useState(null); const [primaryRoverId, setPrimaryRoverId] = useState(null);
const [secondaryRoverId, setSecondaryRoverId] = useState(null);
const [visibleSlot, setVisibleSlot] = useState('primary');
const prewarmTimer = useRef(null); const prewarmTimer = useRef(null);
const activeDrivers = session?.activeDrivers || {}; const activeDrivers = session?.activeDrivers || {};
const driverRoster = useMemo( const driverRoster = useMemo(
@@ -281,6 +283,12 @@ function MiniSummaryContent() {
setIndex(0); setIndex(0);
}, [rotationKey]); }, [rotationKey]);
useEffect(() => {
setPrimaryRoverId(rotationPool[0]?.rover?.id || null);
setSecondaryRoverId(null);
setVisibleSlot('primary');
}, [rotationKey, rotationPool]);
useEffect(() => { useEffect(() => {
if (!rotationPool.length) return undefined; if (!rotationPool.length) return undefined;
const timer = setInterval(() => { const timer = setInterval(() => {
@@ -289,37 +297,63 @@ function MiniSummaryContent() {
return () => clearInterval(timer); return () => clearInterval(timer);
}, [rotationPool.length, rotationKey]); }, [rotationPool.length, rotationKey]);
useEffect(() => {
setPrewarmRoverId(null);
}, [rotationKey]);
useEffect(() => { useEffect(() => {
clearTimeout(prewarmTimer.current); clearTimeout(prewarmTimer.current);
if (!canSpectateVideo || rotationPool.length < 2) { if (!canSpectateVideo || rotationPool.length < 2) {
setPrewarmRoverId(null); setSecondaryRoverId(null);
return undefined; return undefined;
} }
const nextIndex = (index + 1) % rotationPool.length; const nextIndex = (index + 1) % rotationPool.length;
const delay = Math.max(0, ROTATE_MS - PREWARM_MS); const delay = Math.max(0, ROTATE_MS - PREWARM_MS);
prewarmTimer.current = setTimeout(() => { prewarmTimer.current = setTimeout(() => {
const nextEntry = rotationPool[nextIndex]; const nextEntry = rotationPool[nextIndex];
setPrewarmRoverId(nextEntry?.rover?.id || null); const nextId = nextEntry?.rover?.id || null;
if (!nextId) {
setSecondaryRoverId(null);
return;
}
if (visibleSlot === 'primary') {
setSecondaryRoverId(nextId);
} else {
setPrimaryRoverId(nextId);
}
}, delay); }, delay);
return () => clearTimeout(prewarmTimer.current); return () => clearTimeout(prewarmTimer.current);
}, [index, rotationPool, canSpectateVideo]); }, [index, rotationPool, canSpectateVideo, visibleSlot]);
const activeEntry = rotationPool.length ? rotationPool[index % rotationPool.length] : null; const activeEntry = rotationPool.length ? rotationPool[index % rotationPool.length] : null;
const activeRover = activeEntry?.type === 'rover' ? activeEntry.rover : null; const activeRover = activeEntry?.type === 'rover' ? activeEntry.rover : null;
const prewarmRover = prewarmRoverId const activeRoverId = activeRover?.id || null;
? rotationPool.find((entry) => entry.rover?.id === prewarmRoverId)?.rover || null
useEffect(() => {
if (!activeRoverId) return;
if (activeRoverId === primaryRoverId) {
setVisibleSlot('primary');
return;
}
if (activeRoverId === secondaryRoverId) {
setVisibleSlot('secondary');
return;
}
setPrimaryRoverId(activeRoverId);
setVisibleSlot('primary');
}, [activeRoverId, primaryRoverId, secondaryRoverId]);
const primaryRover = primaryRoverId
? rotationPool.find((entry) => entry.rover?.id === primaryRoverId)?.rover || null
: null;
const secondaryRover = secondaryRoverId
? rotationPool.find((entry) => entry.rover?.id === secondaryRoverId)?.rover || null
: null; : null;
const activeSnapshot = !canSpectateVideo && activeRover ? snapshotFeeds[activeRover.id] || null : null; const activeSnapshot = !canSpectateVideo && activeRover ? snapshotFeeds[activeRover.id] || null : null;
const activeVideo = canSpectateVideo && activeRover ? videoSources[activeRover.id] || null : null; const activeVideo = canSpectateVideo && activeRover ? videoSources[activeRover.id] || null : null;
const prewarmVideo = canSpectateVideo && prewarmRover ? videoSources[prewarmRover.id] || null : null; const primaryVideo = canSpectateVideo && primaryRover ? videoSources[primaryRover.id] || null : null;
const secondaryVideo = canSpectateVideo && secondaryRover ? videoSources[secondaryRover.id] || null : null;
const activeAudio = activeRover ? audioSources[`${activeRover.id}-audio`] || null : null; const activeAudio = activeRover ? audioSources[`${activeRover.id}-audio`] || null : null;
const activeFrame = activeRover ? frames[activeRover.id] || null : null; const activeFrame = activeRover ? frames[activeRover.id] || null : null;
const prewarmFrame = prewarmRover ? frames[prewarmRover.id] || null : null; const primaryFrame = primaryRover ? frames[primaryRover.id] || null : null;
const secondaryFrame = secondaryRover ? frames[secondaryRover.id] || null : null;
const driverLabel = activeRover ? formatDriverLabel({ roverId: activeRover.id, session }) : null; const driverLabel = activeRover ? formatDriverLabel({ roverId: activeRover.id, session }) : null;
if (inLockdown) { if (inLockdown) {
@@ -375,31 +409,38 @@ function MiniSummaryContent() {
<FitViewportFrame> <FitViewportFrame>
{canSpectateVideo ? ( {canSpectateVideo ? (
<div className="relative h-full w-full"> <div className="relative h-full w-full">
<div className="absolute inset-0"> {primaryRover ? (
<VideoTile <div
sessionInfo={activeVideo} className={`absolute inset-0 ${visibleSlot === 'primary' ? 'opacity-100' : 'opacity-0 pointer-events-none'}`}
videoMode="whep" >
snapshotFeed={null}
audioSessionInfo={activeAudio}
label={activeRover.name || activeRover.id}
telemetryFrame={activeFrame}
batteryConfig={activeRover.battery}
layoutFormat="mobile"
hudVariant="none"
fitParent
/>
</div>
{prewarmRover && prewarmRover.id !== activeRover.id ? (
<div className="absolute inset-0 opacity-0 pointer-events-none">
<VideoTile <VideoTile
sessionInfo={prewarmVideo} sessionInfo={primaryVideo}
videoMode="whep" videoMode="whep"
snapshotFeed={null} snapshotFeed={null}
audioSessionInfo={null} audioSessionInfo={visibleSlot === 'primary' ? activeAudio : null}
forceMute forceMute={visibleSlot !== 'primary'}
label={prewarmRover.name || prewarmRover.id} label={primaryRover.name || primaryRover.id}
telemetryFrame={prewarmFrame} telemetryFrame={primaryFrame}
batteryConfig={prewarmRover.battery} batteryConfig={primaryRover.battery}
layoutFormat="mobile"
hudVariant="none"
fitParent
/>
</div>
) : null}
{secondaryRover ? (
<div
className={`absolute inset-0 ${visibleSlot === 'secondary' ? 'opacity-100' : 'opacity-0 pointer-events-none'}`}
>
<VideoTile
sessionInfo={secondaryVideo}
videoMode="whep"
snapshotFeed={null}
audioSessionInfo={visibleSlot === 'secondary' ? activeAudio : null}
forceMute={visibleSlot !== 'secondary'}
label={secondaryRover.name || secondaryRover.id}
telemetryFrame={secondaryFrame}
batteryConfig={secondaryRover.battery}
layoutFormat="mobile" layoutFormat="mobile"
hudVariant="none" hudVariant="none"
fitParent fitParent