mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-11-14 10:42:45 -05:00
pause ptz turns when no ones on
This commit is contained in:
@@ -121,7 +121,7 @@ function describeParticipation(socket) {
|
||||
color: cameraConfig.color || DEFAULT_PTZ_COLOR,
|
||||
fallback: null,
|
||||
},
|
||||
enabled: entered && (isOperator || position > 0),
|
||||
enabled: entered && (isOperator || position > 0) && participation.state.queue.length > 0,
|
||||
isActive: isOperator,
|
||||
turnsAhead: isOperator ? 0 : position || null,
|
||||
queueLength: participation.state.queue.length + (participation.state.operatorSocketId ? 1 : 0),
|
||||
|
||||
@@ -22,19 +22,27 @@ function createParticipation({ io, events, emitChange, getTurnDurationMs, canPar
|
||||
}
|
||||
|
||||
function scheduleTurn() {
|
||||
clearTimeout(timer);
|
||||
// Uncontested control has no deadline. Starting a new wait gets a full turn,
|
||||
// while later queue changes must not reset an already running countdown.
|
||||
if (!state.operatorSocketId || !state.queue.length) {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
state.deadline = null;
|
||||
return;
|
||||
}
|
||||
if (timer) return;
|
||||
const duration = getTurnDurationMs();
|
||||
state.deadline = Date.now() + duration;
|
||||
timer = setTimeout(() => {
|
||||
// An expired operator stays when alone, but is not automatically requeued
|
||||
// when another participant takes over. Preserve the existing PTZ rule.
|
||||
state.queue = state.queue.filter((id) => eligible(id));
|
||||
timer = null;
|
||||
state.queue = state.queue.filter(eligible);
|
||||
if (state.queue.length) {
|
||||
// Preserve PTZ's explicit request-to-rejoin rule after a handoff.
|
||||
stopOperator('turn-expired');
|
||||
advance('turn-expired');
|
||||
} else {
|
||||
scheduleTurn();
|
||||
emitChange('turn-extended-empty-queue');
|
||||
emitChange('turn-uncontested');
|
||||
}
|
||||
}, duration);
|
||||
}
|
||||
@@ -45,14 +53,15 @@ function createParticipation({ io, events, emitChange, getTurnDurationMs, canPar
|
||||
}
|
||||
|
||||
function advance(reason) {
|
||||
state.queue = state.queue.filter(eligible);
|
||||
while (!state.operatorSocketId && state.queue.length) {
|
||||
const next = state.queue.shift();
|
||||
if (!eligible(next)) continue;
|
||||
state.operatorSocketId = next;
|
||||
state.generation += 1;
|
||||
scheduleTurn();
|
||||
events.emit('operator', { socketId: next, action: 'active' });
|
||||
}
|
||||
scheduleTurn();
|
||||
emitChange(reason);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ function PtzDesktopFullscreen({ ptz, releasePending }) {
|
||||
</aside>
|
||||
</div>
|
||||
<div className="grid min-h-0 grid-cols-[minmax(0,1.6fr)_minmax(16rem,0.7fr)] gap-0.5 overflow-hidden">
|
||||
<ChatPanel fillHeight title="Chat" allowSpectatorInput inputTarget="overlay" />
|
||||
<ChatPanel fillHeight title="Chat" allowSpectatorInput />
|
||||
<PtzPresetPanel ptz={ptz} />
|
||||
</div>
|
||||
{releasePending ? (
|
||||
@@ -105,7 +105,7 @@ function PtzMobileLandscape({ ptz, onClose, releasePending = false }) {
|
||||
</aside>
|
||||
</section>
|
||||
<section className="grid gap-0.5 md:grid-cols-[minmax(0,1fr)_minmax(0,0.7fr)]">
|
||||
<ChatPanel title="Chat" allowSpectatorInput inputTarget="overlay" />
|
||||
<ChatPanel title="Chat" allowSpectatorInput />
|
||||
<PtzPresetPanel ptz={ptz} />
|
||||
</section>
|
||||
</div>
|
||||
@@ -150,7 +150,7 @@ function PtzMobilePortrait({ ptz, onClose, releasePending = false }) {
|
||||
<PtzPresetPanel ptz={ptz} />
|
||||
</div>
|
||||
<PtzQueueSummary ptz={ptz} />
|
||||
<ChatPanel title="Chat" allowSpectatorInput inputTarget="overlay" />
|
||||
<ChatPanel title="Chat" allowSpectatorInput />
|
||||
{/* Portrait keeps room lights immediately after chat as requested. */}
|
||||
<HomeAssistantControls />
|
||||
</section>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import PtzLiveVideo, { PTZ_CAMERA_ID } from '../../components/PtzLiveVideo/index.jsx';
|
||||
import ChatExpansion from '../../components/HudOverlays/newgen/CornerPods/ChatExpansion.jsx';
|
||||
import TopLeftPod from '../../components/HudOverlays/newgen/CornerPods/TopLeftPod.jsx';
|
||||
import { usePtzCameraSnapshots } from '../../hooks/usePtzCameraSnapshot.js';
|
||||
function PtzSnapshotPreview({ feed, label = 'PTZ Camera', className = 'h-full w-full' }) {
|
||||
@@ -35,6 +36,7 @@ function PtzMediaPane({ ptz, open, framed = true, compact = false }) {
|
||||
<PtzSnapshotPreview feed={snapshot} label={ptz?.name || 'PTZ Camera'} />
|
||||
)}
|
||||
{ptz?.turn ? <TopLeftPod compact={compact} turns={ptz.turn} /> : null}
|
||||
<ChatExpansion podOpen={false} />
|
||||
</>
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user