From 77c25a022ff637a4515550a7df90def016afdd06 Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Tue, 25 May 2021 12:29:16 +0200 Subject: [PATCH 1/4] roll() timer has roll() implementation --- .../common/components/buttons/RollIconBtn.jsx | 1 - server/classes/EventTimer.js | 66 +++++++++++++++++-- server/classes/Timer.js | 3 +- 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/client/src/common/components/buttons/RollIconBtn.jsx b/client/src/common/components/buttons/RollIconBtn.jsx index f34b935c2..079e76f55 100644 --- a/client/src/common/components/buttons/RollIconBtn.jsx +++ b/client/src/common/components/buttons/RollIconBtn.jsx @@ -12,7 +12,6 @@ export default function RollIconBtn(props) { width={120} _focus={{ boxShadow: 'none' }} {...rest} - disabled /> ); } diff --git a/server/classes/EventTimer.js b/server/classes/EventTimer.js index 6059a7a18..fba7d38b0 100644 --- a/server/classes/EventTimer.js +++ b/server/classes/EventTimer.js @@ -109,8 +109,28 @@ class EventTimer extends Timer { update() { // if there is nothing selected, no nothing - if (this.selectedEventId == null) return; - super.update(); + if (this.selectedEventId == null && this.state !== 'roll') return; + + // only implement roll here + if (this.state !== 'roll') { + super.update(); + return; + } + + // get current time + const now = this._getCurrentTime(); + this.clock = now; + + if (this.selectedEventId == null) { + // look for event if none is loaded + this.rollLoad(); + } else if (now > this._finishAt) { + // look for new if finished + this.rollLoad(); + } else { + // update timer as usual + this.current = this._finishAt - now; + } } start() { @@ -140,9 +160,7 @@ class EventTimer extends Timer { else if (payload === 'next') this.next(); else if (payload === 'reload') this.reload(); else if (payload === 'unload') this.unload(); - - // Not yet implemented - // else if (payload === 'roll') this.roll(); + else if (payload === 'roll') this.roll(); this.broadcastThis('playstate', this.state); this.broadcastThis('selected-id', this.selectedEventId); @@ -730,10 +748,44 @@ class EventTimer extends Timer { this.broadcastState(); } + rollLoad() { + const now = this._getCurrentTime(); + this._resetTimers(true); + this._resetSelection(); + + // loop through events, look for where we should be + for (const [index, e] of this._eventlist.entries()) { + if (e.timeStart <= now && now < e.timeEnd) { + // set timers + this._startedAt = e.timeStart; + this._finishAt = e.timeEnd; + this.duration = e.timeEnd - e.timeStart; + this.current = e.timeEnd - now; + + // set selection + this.selectedEventId = e.id; + this.selectedEventIndex = index; + + // set titles + this._loadTitlesNow(); + this._loadTitlesNext(); + // exit + break; + } + } + } + roll() { - console.log('roll: not yet implemented'); - return false; + // do we need to change + if (this.state === 'roll') return; + + // load into event + this.rollLoad(); + + // set state this.state = 'roll'; + + this.broadcastState(); } previous() { diff --git a/server/classes/Timer.js b/server/classes/Timer.js index 6fd83e5e3..1f36c1f5e 100644 --- a/server/classes/Timer.js +++ b/server/classes/Timer.js @@ -110,7 +110,8 @@ class Timer { ); } - _resetTimers() { + _resetTimers(total = false) { + if (total) this.duration = null; this.current = this.duration; this._finishAt = null; this._finishedAt = null; From d311703025a8022d09aa55a9d10709aaf0ecda2a Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Wed, 26 May 2021 12:39:36 +0200 Subject: [PATCH 2/4] countdown to upcoming --- server/classes/EventTimer.js | 116 ++++++++++++++++++++++++++++------- server/classes/Timer.js | 4 +- 2 files changed, 98 insertions(+), 22 deletions(-) diff --git a/server/classes/EventTimer.js b/server/classes/EventTimer.js index fba7d38b0..b7c8a03f2 100644 --- a/server/classes/EventTimer.js +++ b/server/classes/EventTimer.js @@ -121,15 +121,16 @@ class EventTimer extends Timer { const now = this._getCurrentTime(); this.clock = now; - if (this.selectedEventId == null) { - // look for event if none is loaded - this.rollLoad(); - } else if (now > this._finishAt) { - // look for new if finished - this.rollLoad(); - } else { + if (this.selectedEventId && this.current > 0) { // update timer as usual this.current = this._finishAt - now; + } else { + // look for event if none is loaded + if (this.current <= 0 || this.secondaryTimer <= 0) this.rollLoad(); + + // count to next event + // TODO: replace with proper counter + if (this.secondaryTimer != null) this.secondaryTimer -= 1000; } } @@ -162,6 +163,9 @@ class EventTimer extends Timer { else if (payload === 'unload') this.unload(); else if (payload === 'roll') this.roll(); + // TODO: Cleanup + // here tdo this.broadcastState; + // remove broadcast from functions this.broadcastThis('playstate', this.state); this.broadcastThis('selected-id', this.selectedEventId); this.broadcastThis('titles', this.titles); @@ -577,6 +581,42 @@ class EventTimer extends Timer { } } + _loadThisTitles(eventIndex, type) { + if (eventIndex < 0 || eventIndex >= this.numEvents) return; + const e = this._eventlist[eventIndex]; + + switch (type) { + // now, load to both public and private + case 'now': + break; + case 'now-public': + break; + case 'now-private': + break; + + // next, load to both public and private + case 'next': + this.titles.titleNext = e.title; + this.titles.subtitleNext = e.subtitle; + this.titles.presenterNext = e.presenter; + this.nextEventId = e.id; + + this.titlesPublic.titleNext = e.title; + this.titlesPublic.subtitleNext = e.subtitle; + this.titlesPublic.presenterNext = e.presenter; + this.nextPublicEventId = e.id; + + break; + case 'next-public': + break; + case 'next-private': + break; + + default: + break; + } + } + _loadTitlesNext() { // maybe there is nothing to load if (this.selectedEventIndex == null) return; @@ -660,6 +700,7 @@ class EventTimer extends Timer { state = ${this.state} current = ${this.current} duration = ${this.duration} + secondaryTimer = ${this.secondaryTimer} Events ------------------------------ @@ -753,24 +794,57 @@ class EventTimer extends Timer { this._resetTimers(true); this._resetSelection(); + let foundNow = null; + let nextIndex = null; + let nextStart = null; + // loop through events, look for where we should be for (const [index, e] of this._eventlist.entries()) { - if (e.timeStart <= now && now < e.timeEnd) { - // set timers - this._startedAt = e.timeStart; - this._finishAt = e.timeEnd; - this.duration = e.timeEnd - e.timeStart; - this.current = e.timeEnd - now; + if (!foundNow) { + if (e.timeStart <= now && now < e.timeEnd) { + // set flag + foundNow = true; - // set selection - this.selectedEventId = e.id; - this.selectedEventIndex = index; + // set timers + this._startedAt = e.timeStart; + this._finishAt = e.timeEnd; + this.duration = e.timeEnd - e.timeStart; + this.current = e.timeEnd - now; - // set titles - this._loadTitlesNow(); - this._loadTitlesNext(); - // exit - break; + // set selection + this.selectedEventId = e.id; + this.selectedEventIndex = index; + + // set titles + this._loadTitlesNow(); + + // skip this entry for next + continue; + } + } + // check how far the start is from now + let wait = e.timeStart - now; + if (wait > 0) { + if (nextStart == null || wait < nextStart) { + nextStart = wait; + nextIndex = index; + } + } + } + + // nothing to play next, unload + if (!foundNow && !nextIndex) { + this.unload(); + return; + } + + if (nextIndex) { + // load titles + this._loadThisTitles(nextIndex, 'next'); + + if (!foundNow) { + // timer counts to nextStart + this.secondaryTimer = nextStart; } } } diff --git a/server/classes/Timer.js b/server/classes/Timer.js index 1f36c1f5e..bfca06682 100644 --- a/server/classes/Timer.js +++ b/server/classes/Timer.js @@ -8,6 +8,7 @@ class Timer { clock = null; duration = null; current = null; + secondaryTimer = null; _finishAt = null; _finishedAt = null; _startedAt = null; @@ -113,6 +114,7 @@ class Timer { _resetTimers(total = false) { if (total) this.duration = null; this.current = this.duration; + this.secondaryTimer = null; this._finishAt = null; this._finishedAt = null; this._startedAt = null; @@ -133,7 +135,7 @@ class Timer { return { clock: this.clock, running: Timer.toSeconds(this.current), - currentSeconds: Timer.toSeconds(Math.max(this.current, 0)), + secondary: Timer.toSeconds(this.secondaryTimer), durationSeconds: Timer.toSeconds(this.duration), expectedFinish: this._getExpectedFinish(), startedAt: this._startedAt, From f78c16fb8c94549dc8212085a56cbf2ad374dbad Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Wed, 26 May 2021 13:10:23 +0200 Subject: [PATCH 3/4] style + cleanup --- .../src/features/control/PlaybackButtons.jsx | 5 +- .../src/features/control/PlaybackControl.jsx | 1 + .../control/PlaybackControl.module.css | 7 +- client/src/features/control/PlaybackTimer.jsx | 34 ++++++--- server/classes/EventTimer.js | 71 +++++++++++-------- 5 files changed, 74 insertions(+), 44 deletions(-) diff --git a/client/src/features/control/PlaybackButtons.jsx b/client/src/features/control/PlaybackButtons.jsx index 4b46ab07b..8958bba51 100644 --- a/client/src/features/control/PlaybackButtons.jsx +++ b/client/src/features/control/PlaybackButtons.jsx @@ -41,10 +41,7 @@ const Transport = ({ selectedId, playbackControl }) => {
playbackControl('previous')} /> playbackControl('next')} /> - playbackControl('unload')} - disabled={!selectedId} - /> + playbackControl('unload')} /> playbackControl('reload')} disabled={!selectedId} diff --git a/client/src/features/control/PlaybackControl.jsx b/client/src/features/control/PlaybackControl.jsx index d5881f9a2..af1201774 100644 --- a/client/src/features/control/PlaybackControl.jsx +++ b/client/src/features/control/PlaybackControl.jsx @@ -90,6 +90,7 @@ export default function PlaybackControl() {
socket.emit('increment-timer', amount)} /> { return ( prevProps.timer.running === nextProps.timer.running && prevProps.timer.expectedFinish === nextProps.timer.expectedFinish && - prevProps.timer.startedAt === nextProps.timer.startedAt + prevProps.timer.startedAt === nextProps.timer.startedAt && + prevProps.playback === nextProps.playback ); }; -const PlaybackTimer = ({ timer, handleIncrement }) => { +const PlaybackTimer = (props) => { + const { timer, playback, handleIncrement } = props; const started = stringFromMillis(timer.startedAt, true); const finish = stringFromMillis(timer.expectedFinish, true); const isNegative = timer.running < 0; const isDelayed = false; - const isRolling = false; + const isRolling = playback === 'roll'; const incrementProps = { size: 'sm', @@ -31,7 +33,7 @@ const PlaybackTimer = ({ timer, handleIncrement }) => { <>
-
+
@@ -49,16 +51,32 @@ const PlaybackTimer = ({ timer, handleIncrement }) => { {finish}
- - - -
diff --git a/server/classes/EventTimer.js b/server/classes/EventTimer.js index b7c8a03f2..07ee230eb 100644 --- a/server/classes/EventTimer.js +++ b/server/classes/EventTimer.js @@ -544,18 +544,12 @@ class EventTimer extends Timer { if (e == null) return; // private title is always current - this.titles.titleNow = e.title; - this.titles.subtitleNow = e.subtitle; - this.titles.presenterNow = e.presenter; - this.selectedEventId = e.id; - // check if current is also public if (e.isPublic) { - this.titlesPublic.titleNow = e.title; - this.titlesPublic.subtitleNow = e.subtitle; - this.titlesPublic.presenterNow = e.presenter; - this.selectedPublicEventId = e.id; + this._loadThisTitles(e, 'now'); } else { + this._loadThisTitles(e, 'now-private'); + // assume there is no public event this.titlesPublic.titleNow = null; this.titlesPublic.subtitleNow = null; @@ -571,45 +565,70 @@ class EventTimer extends Timer { this._eventlist[i].type === 'event' && this._eventlist[i].isPublic ) { - this.titlesPublic.titleNow = this._eventlist[i].title; - this.titlesPublic.subtitleNow = this._eventlist[i].subtitle; - this.titlesPublic.presenterNow = this._eventlist[i].presenter; - this.selectedPublicEventId = this._eventlist[i].id; + this._loadThisTitles(this._eventlist[i], 'now-public'); break; } } } } - _loadThisTitles(eventIndex, type) { - if (eventIndex < 0 || eventIndex >= this.numEvents) return; - const e = this._eventlist[eventIndex]; + _loadThisTitles(e, type) { + if (e == null) return; switch (type) { // now, load to both public and private case 'now': + // public + this.titlesPublic.titleNow = e.title; + this.titlesPublic.subtitleNow = e.subtitle; + this.titlesPublic.presenterNow = e.presenter; + this.selectedPublicEventId = e.id; + + // private + this.titles.titleNow = e.title; + this.titles.subtitleNow = e.subtitle; + this.titles.presenterNow = e.presenter; + this.selectedEventId = e.id; + break; case 'now-public': + this.titlesPublic.titleNow = e.title; + this.titlesPublic.subtitleNow = e.subtitle; + this.titlesPublic.presenterNow = e.presenter; + this.selectedPublicEventId = e.id; break; case 'now-private': + this.titles.titleNow = e.title; + this.titles.subtitleNow = e.subtitle; + this.titles.presenterNow = e.presenter; + this.selectedEventId = e.id; break; // next, load to both public and private case 'next': - this.titles.titleNext = e.title; - this.titles.subtitleNext = e.subtitle; - this.titles.presenterNext = e.presenter; - this.nextEventId = e.id; - + // public this.titlesPublic.titleNext = e.title; this.titlesPublic.subtitleNext = e.subtitle; this.titlesPublic.presenterNext = e.presenter; this.nextPublicEventId = e.id; + // private + this.titles.titleNext = e.title; + this.titles.subtitleNext = e.subtitle; + this.titles.presenterNext = e.presenter; + this.nextEventId = e.id; break; case 'next-public': + this.titlesPublic.titleNext = e.title; + this.titlesPublic.subtitleNext = e.subtitle; + this.titlesPublic.presenterNext = e.presenter; + this.nextPublicEventId = e.id; break; case 'next-private': + this.titles.titleNext = e.title; + this.titles.subtitleNext = e.subtitle; + this.titles.presenterNext = e.presenter; + this.nextEventId = e.id; break; default: @@ -641,19 +660,13 @@ class EventTimer extends Timer { if (this._eventlist[i].type === 'event') { // if we have not set private if (!nextPrivate) { - this.titles.titleNext = this._eventlist[i].title; - this.titles.subtitleNext = this._eventlist[i].subtitle; - this.titles.presenterNext = this._eventlist[i].presenter; - this.nextEventId = this._eventlist[i].id; + this._loadThisTitles(this._eventlist[i], 'next-private'); nextPrivate = true; } // if event is public if (this._eventlist[i].isPublic) { - this.titlesPublic.titleNext = this._eventlist[i].title; - this.titlesPublic.subtitleNext = this._eventlist[i].subtitle; - this.titlesPublic.presenterNext = this._eventlist[i].presenter; - this.nextPublicEventId = this._eventlist[i].id; + this._loadThisTitles(this._eventlist[i], 'next-public'); nextPublic = true; } } From c310249cd376655cf0e3361c0b6ef21bb0cc3f1a Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Wed, 26 May 2021 20:42:05 +0200 Subject: [PATCH 4/4] fix: presenter view presenter view shows time correctly when rolling --- client/src/features/viewers/ViewWrapper.jsx | 4 ++-- client/src/features/viewers/presenter/PresenterView.jsx | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/client/src/features/viewers/ViewWrapper.jsx b/client/src/features/viewers/ViewWrapper.jsx index 6e198eac3..738d6acfb 100644 --- a/client/src/features/viewers/ViewWrapper.jsx +++ b/client/src/features/viewers/ViewWrapper.jsx @@ -37,7 +37,7 @@ const withSocket = (Component) => { }); const [timer, setTimer] = useState({ clock: null, - currentSeconds: null, + running: null, startedAt: null, expectedFinish: null, }); @@ -221,7 +221,7 @@ const withSocket = (Component) => { // get clock string const timeManager = { ...timer, - finished: timer.running <= 0 && timer.startedAt, + finished: playback === 'start' && timer.running <= 0 && timer.startedAt, clock: stringFromMillis(timer.clock), playstate: playback, }; diff --git a/client/src/features/viewers/presenter/PresenterView.jsx b/client/src/features/viewers/presenter/PresenterView.jsx index 5d76d6df7..53a74faab 100644 --- a/client/src/features/viewers/presenter/PresenterView.jsx +++ b/client/src/features/viewers/presenter/PresenterView.jsx @@ -14,10 +14,9 @@ export default function PresenterView(props) { document.title = 'ontime - Speaker Screen'; }, []); - - const showOverlay = pres.text !== '' && pres.visible; - const isPlaying = time.playstate === 'start'; + const isPlaying = time.playstate !== 'pause'; + const normalisedTime = Math.max(time.running, 0); // motion const titleVariants = { @@ -61,7 +60,7 @@ export default function PresenterView(props) {
TIME UP
) : (
- +
)}
@@ -73,7 +72,7 @@ export default function PresenterView(props) { } >