diff --git a/client/src/common/components/buttons/UnloadIconBtn.jsx b/client/src/common/components/buttons/UnloadIconBtn.jsx index e27d5a29d..c5c5f1812 100644 --- a/client/src/common/components/buttons/UnloadIconBtn.jsx +++ b/client/src/common/components/buttons/UnloadIconBtn.jsx @@ -6,8 +6,8 @@ export default function UnloadIconBtn(props) { return ( } - colorScheme='whiteAlpha' - backgroundColor='#ffffff05' + colorScheme='red' + backgroundColor='#ff000022' variant='outline' onClick={clickhandler} width={90} diff --git a/client/src/features/control/PlaybackButtons.jsx b/client/src/features/control/PlaybackButtons.jsx index 081795df7..624aff651 100644 --- a/client/src/features/control/PlaybackButtons.jsx +++ b/client/src/features/control/PlaybackButtons.jsx @@ -16,17 +16,18 @@ const areEqual = (prevProps, nextProps) => { }; const Playback = ({ playback, selectedId, playbackControl }) => { + const isRolling = playback === 'roll'; return (
playbackControl('start')} - disabled={!selectedId} + disabled={!selectedId || isRolling} /> playbackControl('pause')} - disabled={!selectedId} + disabled={!selectedId || isRolling} /> { }; const Transport = ({ playback, selectedId, playbackControl }) => { + const isRolling = playback === 'roll'; return (
{ /> playbackControl('reload')} - disabled={!selectedId} + disabled={!selectedId || isRolling} + /> + playbackControl('unload')} + disabled={!selectedId && !isRolling} /> - playbackControl('unload')} />
); }; diff --git a/server/src/classes/EventTimer.js b/server/src/classes/EventTimer.js index 89b4433b0..64ba0c383 100644 --- a/server/src/classes/EventTimer.js +++ b/server/src/classes/EventTimer.js @@ -203,8 +203,8 @@ export class EventTimer extends Timer { } // broadcast state - broadcastState() { - this.io.emit('timer', this.getObject()); + broadcastState(update = true) { + this.io.emit('timer', this.getObject(update)); this.io.emit('playstate', this.state); this.io.emit('selected', { id: this.selectedEventId, @@ -232,16 +232,28 @@ export class EventTimer extends Timer { if (this.state !== 'roll') { super.update(); } else { - // get current time + // update timer as usual const now = this._getCurrentTime(); this.clock = now; - if (this.selectedEventId && this.current > 0) { - // update timer as usual + // something is running, update this.current = this._finishAt - now; - } else { - // look for event if none is loaded - if (this.current <= 0 || this.secondaryTimer <= 0) this.rollLoad(); + } else if (this.secondaryTimer > 0) { + // waiting to start, update secondary + this.secondaryTimer = this._secondaryTarget - now; + } + + // look for event if none is loaded + const currentRunning = this.current <= 0 && this.current !== null; + const secondaryRunning = + this.secondaryTimer <= 0 && this.secondaryTimer !== null; + + if (currentRunning || secondaryRunning) { + // look for events + this.rollLoad(); + + // broadcast state without recalculating timer + this.broadcastState(false); } } @@ -561,6 +573,11 @@ export class EventTimer extends Timer { ? 'reload' : 'load'; this.loadEvent(this.selectedEventIndex, type); + } else if (e.id === this.nextEventId) { + // roll needs to recalculate + if (this.state === 'roll') { + this.rollLoad(); + } } else if ('title' in e || 'subtitle' in e || 'presenter') { // TODO: should be more selective on the need to load titles this._loadTitlesNext(); @@ -956,15 +973,25 @@ export class EventTimer extends Timer { // loop through events, look for where we should be for (const [index, e] of this._eventlist.entries()) { if (!foundNow) { - if (e.timeStart <= now && now < e.timeEnd) { + let normalEnd = e.timeEnd; + + // handle midnight + if (normalEnd < e.timeStart) { + normalEnd += this.DAYMS; + } + + if (e.timeStart <= now && now < normalEnd) { // set flag foundNow = true; // set timers + this.secondaryTimer = null; + this._secondaryTarget = null; + this._startedAt = e.timeStart; - this._finishAt = e.timeEnd; - this.duration = e.timeEnd - e.timeStart; - this.current = e.timeEnd - now; + this._finishAt = normalEnd; + this.duration = normalEnd - e.timeStart; + this.current = normalEnd - now; // set selection this.selectedEventId = e.id; @@ -987,23 +1014,29 @@ export class EventTimer extends Timer { } } - // nothing to play next, unload + // nothing to play, unload if (foundNow == null && nextIndex == null) { this.unload(); console.log('Roll: no events found'); return; } + // we found something to play next if (nextIndex != null) { - // load titles const e = this._eventlist[nextIndex]; this._loadThisTitles(e, 'next'); if (foundNow == null) { + // only warn the first time if (this.secondaryTimer == null) console.log('Roll: waiting for event start'); + + // reset running timer + this.current = null; + // timer counts to nextStart this.secondaryTimer = nextStart; + this._secondaryTarget = e.timeStart; } } } @@ -1012,12 +1045,12 @@ export class EventTimer extends Timer { // do we need to change if (this.state === 'roll') return; - // load into event - this.rollLoad(); - // set state this.state = 'roll'; + // load into event + this.rollLoad(); + this.broadcastState(); } diff --git a/server/src/classes/Timer.js b/server/src/classes/Timer.js index 4ee9d750a..01ed79dcf 100644 --- a/server/src/classes/Timer.js +++ b/server/src/classes/Timer.js @@ -12,6 +12,7 @@ export class Timer { current = null; timeTag = null; secondaryTimer = null; + _secondaryTarget = null; _finishAt = null; _finishedAt = null; _startedAt = null; @@ -125,6 +126,7 @@ export class Timer { this.current = this.duration; this.running = null; this.secondaryTimer = null; + this._secondaryTarget = null; this._finishAt = null; this._finishedAt = null; this._startedAt = null; @@ -139,9 +141,9 @@ export class Timer { } // getObject - getObject() { + getObject(update = true) { // update timer - this.update(); + if (update) this.update(); // update timetag this.timeTag = stringFromMillis(this.current);