From b252aa19b9f819aeb70ab1c6234f8761a0bea714 Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Tue, 25 May 2021 10:19:54 +0200 Subject: [PATCH 01/14] fix: simplify time input --- client/src/common/input/EditableTimer.jsx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/client/src/common/input/EditableTimer.jsx b/client/src/common/input/EditableTimer.jsx index 2c771dbbf..2c39dd6d8 100644 --- a/client/src/common/input/EditableTimer.jsx +++ b/client/src/common/input/EditableTimer.jsx @@ -34,12 +34,12 @@ export default function EditableTimer(props) { if (value === '') return false; // Time now and time submitedVal - const original = stringFromMillis(time, false); + const original = stringFromMillis(time + delay, false); // check if time is different from before if (value === original) return false; - // conver to millis object + // convert to millis object const millis = timeStringToMillis(value, timeFormat); // validate with parent @@ -51,14 +51,8 @@ export default function EditableTimer(props) { return true; }; - const showOriginal = () => { - setValue(stringFromMillis(time, false)); - }; - return ( showOriginal} - onEdit={() => showOriginal} onChange={(v) => setValue(v)} onSubmit={(v) => validateValue(v)} value={value} 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 02/14] 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 8f754587fa25fbf8718c8480eaee45930fd7069e Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Tue, 25 May 2021 22:14:40 +0200 Subject: [PATCH 03/14] bugfix: osc gotoid - typo in loadEvent call - force string on osc parameter call --- server/classes/EventTimer.js | 2 +- server/controllers/OscController.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/classes/EventTimer.js b/server/classes/EventTimer.js index 6059a7a18..9bc3443bb 100644 --- a/server/classes/EventTimer.js +++ b/server/classes/EventTimer.js @@ -472,7 +472,7 @@ class EventTimer extends Timer { if (eventIndex === -1) return; this.pause(); - this.loadEvent(eventIndex, true, true); + this.loadEvent(eventIndex, 'load', true); } // Loads a given event diff --git a/server/controllers/OscController.js b/server/controllers/OscController.js index 288e5ee5e..488442002 100644 --- a/server/controllers/OscController.js +++ b/server/controllers/OscController.js @@ -71,7 +71,7 @@ const initiateOSC = (config) => { case 'gotoid': console.log('calling gotoid with', args); try { - global.timer.loadEventById(args.toLowerCase()); + global.timer.loadEventById(args.toString().toLowerCase()); } catch (error) { console.log('error calling goto: ', error); } From 447fede0ff34893e3fc9bb26c267646362c937f4 Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Tue, 25 May 2021 22:35:38 +0200 Subject: [PATCH 04/14] style: clarify OSC triggers - show path for goto - show path for gotoid --- client/src/features/editors/list/EventBlock.jsx | 10 +++++++--- client/src/features/editors/list/EventList.jsx | 14 ++++++++++++-- client/src/features/editors/list/EventListItem.jsx | 2 ++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/client/src/features/editors/list/EventBlock.jsx b/client/src/features/editors/list/EventBlock.jsx index 62cf829b5..6cc78f21d 100644 --- a/client/src/features/editors/list/EventBlock.jsx +++ b/client/src/features/editors/list/EventBlock.jsx @@ -14,7 +14,8 @@ import { SelectCollapse, HandleCollapse } from 'app/context/collapseAtom'; import { useAtom } from 'jotai'; const ExpandedBlock = (props) => { - const { provided, data, next, delay, delayValue, actionHandler } = props; + const { provided, data, eventIndex, next, delay, delayValue, actionHandler } = + props; const oscid = data.id.length > 4 ? '...' : data.id; @@ -80,7 +81,9 @@ const ExpandedBlock = (props) => { actionHandler('update', { field: 'note', value: v }) } /> - {`OSC ID: ${oscid}`} + + {`/ontime/goto ${eventIndex} << OSC >> /ontime/gotoid ${oscid}`} + { }; export default function EventBlock(props) { - const { data, selected, delay, index, actionHandler } = props; + const { data, selected, delay, index, eventIndex, actionHandler } = props; // const [collapsed, setCollapsed] = useState(checkLocalStorage(data.id)); @@ -200,6 +203,7 @@ export default function EventBlock(props) { ) : ( {events.map((e, index) => { let isCursor = cursor === index; - if (index === 0) cumulativeDelay = 0; + if (index === 0) { + cumulativeDelay = 0; + eventIndex = -1; + } if (e.type === 'delay' && e.duration != null) { cumulativeDelay += e.duration; - } else if (e.type === 'block') cumulativeDelay = 0; + } else if (e.type === 'block') { + cumulativeDelay = 0; + } else if (e.type === 'event') { + eventIndex++; + } + return (
{ const { type, index, + eventIndex, data, selected, next, @@ -71,6 +72,7 @@ const EventListItem = (props) => { return ( Date: Tue, 25 May 2021 23:03:03 +0200 Subject: [PATCH 05/14] bugfix: cursor follows playback fix bug where cursor would not check for delay and block modules --- .../src/features/editors/list/EventList.jsx | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/client/src/features/editors/list/EventList.jsx b/client/src/features/editors/list/EventList.jsx index bd581fc0a..1ff4772c4 100644 --- a/client/src/features/editors/list/EventList.jsx +++ b/client/src/features/editors/list/EventList.jsx @@ -27,7 +27,7 @@ export default function EventList(props) { }, 'Alt+ArrowUp': () => { if (cursor == null) setCursor(0); - else if (cursor >= 0) setCursor(cursor - 1); + else if (cursor > 0) setCursor(cursor - 1); }, 'Alt+KeyE': (event) => { event.preventDefault(); @@ -49,7 +49,7 @@ export default function EventList(props) { return () => { unsubscribe(); }; - }, [cursor, events.length, eventsHandler]); + }, [cursor, events, eventsHandler]); // handle incoming messages useEffect(() => { @@ -62,7 +62,6 @@ export default function EventList(props) { // Handle playstate socket.on('selected', (data) => { setSelected(data); - console.log('debug cursor setted', data); }); socket.on('next-id', (data) => { setNext(data); @@ -80,13 +79,20 @@ export default function EventList(props) { if (cursorSettings !== 'locked' || selected == null) return; if (selected.index == null) return; - setCursor(selected.index); - }, [selected, cursorSettings]); + let eventIndex = -1; + let gotoIndex = -1; + for (const e of events) { + gotoIndex++; + if (e.type === 'event') eventIndex++; + if (eventIndex === selected.index) break; + } + + setCursor(gotoIndex); + }, [events, selected, cursorSettings]); // attach scroll to cursor useEffect(() => { if (cursor == null || cursorRef.current == null) return; - console.log('debug cursor scrolling'); cursorRef.current.scrollIntoView({ behavior: 'smooth', @@ -119,8 +125,6 @@ export default function EventList(props) { let cumulativeDelay = 0; let eventIndex = -1; - console.log('debug selected', selected); - return (
@@ -132,7 +136,6 @@ export default function EventList(props) { ref={provided.innerRef} > {events.map((e, index) => { - let isCursor = cursor === index; if (index === 0) { cumulativeDelay = 0; eventIndex = -1; @@ -147,9 +150,9 @@ export default function EventList(props) { return (
Date: Tue, 25 May 2021 23:14:56 +0200 Subject: [PATCH 06/14] bugfix: timer negative on goto when jumping events using goto, start time would not be set --- server/classes/Timer.js | 3 +++ server/controllers/OscController.js | 1 + 2 files changed, 4 insertions(+) diff --git a/server/classes/Timer.js b/server/classes/Timer.js index 6fd83e5e3..d322c8bf4 100644 --- a/server/classes/Timer.js +++ b/server/classes/Timer.js @@ -50,6 +50,9 @@ class Timer { // check playstate switch (this.state) { case 'start': + // ensure we have a start time + if (this._startedAt == null) this._startedAt = now; + // update current timer this.current = this._startedAt + this.duration + this._pausedTotal - now; diff --git a/server/controllers/OscController.js b/server/controllers/OscController.js index 488442002..dba6d9cc1 100644 --- a/server/controllers/OscController.js +++ b/server/controllers/OscController.js @@ -63,6 +63,7 @@ const initiateOSC = (config) => { try { let eventIndex = parseInt(args); if (isNaN(eventIndex) || eventIndex <= 0) return; + global.timer.pause(); global.timer.loadEvent(eventIndex - 1, undefined, true); } catch (error) { console.log('error calling goto: ', error); From 9c55116053e9ce96a17277088314989d70671552 Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Wed, 26 May 2021 10:14:40 +0200 Subject: [PATCH 07/14] fix: show event index as 1 based --- client/src/features/editors/list/EventBlock.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/features/editors/list/EventBlock.jsx b/client/src/features/editors/list/EventBlock.jsx index 6cc78f21d..9b26ea583 100644 --- a/client/src/features/editors/list/EventBlock.jsx +++ b/client/src/features/editors/list/EventBlock.jsx @@ -82,7 +82,7 @@ const ExpandedBlock = (props) => { } /> - {`/ontime/goto ${eventIndex} << OSC >> /ontime/gotoid ${oscid}`} + {`/ontime/goto ${eventIndex + 1} << OSC >> /ontime/gotoid ${oscid}`}
Date: Wed, 26 May 2021 12:39:36 +0200 Subject: [PATCH 08/14] 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 09/14] 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 10/14] 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) { } > From 0a2be1615eb3aee79520cc4a5dd9c7ee7a6c02f7 Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Wed, 26 May 2021 20:44:09 +0200 Subject: [PATCH 11/14] improve: stop list rerender react-query would trigger re-render on refetch even when using cache --- client/src/app/hooks/useFetch.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/app/hooks/useFetch.js b/client/src/app/hooks/useFetch.js index 3ddbdeaba..eceaf10d8 100644 --- a/client/src/app/hooks/useFetch.js +++ b/client/src/app/hooks/useFetch.js @@ -5,6 +5,7 @@ export const useFetch = (namespace, fn) => { const { data, status, isError, refetch } = useQuery(namespace, fn, { refetchInterval: refetchIntervalMs, cacheTime: Infinity, + notifyOnChangeProps: 'tracked', }); return { data, status, isError, refetch }; From 856f9d308ad22edcf5d45eadacc0087542a39a50 Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Wed, 26 May 2021 22:19:55 +0200 Subject: [PATCH 12/14] small style fixes + defaults - remove unused code in collapse atom - stop text input from creating new line - clean overflow - restyle lock button - restyle action buttons - 10 second default on paginator - Pip shows running timer --- client/src/App.css | 2 +- client/src/app/context/collapseAtom.js | 9 --------- client/src/common/components/buttons/LockIconBtn.jsx | 5 +++-- client/src/common/components/views/Paginator.jsx | 2 +- client/src/common/input/EditableText.jsx | 4 ++-- client/src/features/editors/Editor.module.css | 10 ++++++++-- client/src/features/editors/list/ActionButtons.jsx | 2 +- client/src/features/menu/MenuActionButtons.jsx | 2 +- client/src/features/viewers/backstage/StageManager.jsx | 2 +- client/src/features/viewers/production/Pip.jsx | 7 ++----- 10 files changed, 20 insertions(+), 25 deletions(-) diff --git a/client/src/App.css b/client/src/App.css index b28937f73..27fa5fcf3 100644 --- a/client/src/App.css +++ b/client/src/App.css @@ -7,6 +7,6 @@ body, html, .App { margin: 0px auto; - overflow: hidden; + overflow: clip; height: 100vh; } diff --git a/client/src/app/context/collapseAtom.js b/client/src/app/context/collapseAtom.js index 57ee2a9e4..ed6b63bc3 100644 --- a/client/src/app/context/collapseAtom.js +++ b/client/src/app/context/collapseAtom.js @@ -58,12 +58,3 @@ export const BatchOperation = atom(null, (get, set, payload) => { localStorage.setItem(PATH, JSON.stringify(options)); }); - -// change collapsed in all items -export const setAll = async (items, isCollapsed) => { - // clear storage - localStorage.removeItem(PATH); - - // call batch - BatchOperation({ items: items, isCollapsed: isCollapsed }); -}; diff --git a/client/src/common/components/buttons/LockIconBtn.jsx b/client/src/common/components/buttons/LockIconBtn.jsx index d52030fd1..c499594d0 100644 --- a/client/src/common/components/buttons/LockIconBtn.jsx +++ b/client/src/common/components/buttons/LockIconBtn.jsx @@ -10,8 +10,9 @@ export default function LockIconBtn(props) { ref={ref} size={props.size || 'xs'} icon={} - colorScheme='pink' - color={'pink.300'} + color={active ? 'pink.100' : 'pink.300'} + borderColor={active ? undefined : 'pink.300'} + backgroundColor={active ? 'pink.300' : undefined} variant={active ? 'solid' : 'outline'} onClick={clickhandler} _focus={{ boxShadow: 'none' }} diff --git a/client/src/common/components/views/Paginator.jsx b/client/src/common/components/views/Paginator.jsx index 540fddf4f..9fcb89762 100644 --- a/client/src/common/components/views/Paginator.jsx +++ b/client/src/common/components/views/Paginator.jsx @@ -6,7 +6,7 @@ import { useInterval } from 'app/hooks/useInterval'; export default function Paginator(props) { const { events, selectedId } = props; const LIMIT_PER_PAGE = props.limit || 8; - const SCROLL_TIME = props.time * 1000 || 5000; + const SCROLL_TIME = props.time * 1000 || 10000; const SCROLL_PAST = false; const [numEvents, setNumEvents] = useState(0); const [page, setPage] = useState([]); diff --git a/client/src/common/input/EditableText.jsx b/client/src/common/input/EditableText.jsx index 73739d6c2..f41d8ad0a 100644 --- a/client/src/common/input/EditableText.jsx +++ b/client/src/common/input/EditableText.jsx @@ -33,9 +33,9 @@ export default function EditableText(props) { > - +
); diff --git a/client/src/features/editors/Editor.module.css b/client/src/features/editors/Editor.module.css index 3e20053c6..73563ae0c 100644 --- a/client/src/features/editors/Editor.module.css +++ b/client/src/features/editors/Editor.module.css @@ -18,11 +18,12 @@ /* 2/3 window, hide previews */ @media (max-width: 1250px) and (min-height: 700px) { .mainContainer { + height: 100%; grid-template-rows: 1fr 1fr; grid-template-columns: 48em 1fr 1fr; - grid-template-areas: + /* grid-template-areas: 'even play sett' - 'even mess sett'; + 'even mess sett'; */ } .info { @@ -40,6 +41,11 @@ 'play'; } + .messages, + .playback { + min-width: 31em; + } + .editor, .info, .settings { diff --git a/client/src/features/editors/list/ActionButtons.jsx b/client/src/features/editors/list/ActionButtons.jsx index 8c1d2bff4..ddd673728 100644 --- a/client/src/features/editors/list/ActionButtons.jsx +++ b/client/src/features/editors/list/ActionButtons.jsx @@ -17,7 +17,7 @@ export default function ActionButtons(props) { aria-label='Options' size='xs' icon={} - _expanded={{ bg: 'pink.300', color: 'white' }} + _expanded={{ bg: 'orange.300', color: 'white' }} _focus={{ boxShadow: 'none' }} backgroundColor={'orange.200'} color={'orange.500'} diff --git a/client/src/features/menu/MenuActionButtons.jsx b/client/src/features/menu/MenuActionButtons.jsx index eff31e739..4bb954e40 100644 --- a/client/src/features/menu/MenuActionButtons.jsx +++ b/client/src/features/menu/MenuActionButtons.jsx @@ -23,7 +23,7 @@ export default function MenuActionButtons(props) { aria-label='Options' size={props.size || 'xs'} icon={} - _expanded={{ bg: 'pink.300', color: 'white' }} + _expanded={{ bg: 'orange.300', color: 'white' }} _focus={{ boxShadow: 'none' }} backgroundColor={'orange.200'} color={'orange.500'} diff --git a/client/src/features/viewers/backstage/StageManager.jsx b/client/src/features/viewers/backstage/StageManager.jsx index 0fa299413..6ee5cadc8 100644 --- a/client/src/features/viewers/backstage/StageManager.jsx +++ b/client/src/features/viewers/backstage/StageManager.jsx @@ -42,7 +42,7 @@ export default function StageManager(props) { // Format messages const showPubl = publ.text !== '' && publ.visible; let stageTimer = formatDisplay(Math.abs(time.running), true); - if (time.running < 0) stageTimer = '-' + stageTimer; + if (time.running < 0) stageTimer = `-${stageTimer}`; // motion const titleVariants = { diff --git a/client/src/features/viewers/production/Pip.jsx b/client/src/features/viewers/production/Pip.jsx index c2dbe6d8d..15d6385a0 100644 --- a/client/src/features/viewers/production/Pip.jsx +++ b/client/src/features/viewers/production/Pip.jsx @@ -51,11 +51,8 @@ export default function Pip(props) { // Format messages const showInfo = general.backstageInfo !== '' && general.backstageInfo != null; - - const stageTimer = - time.currentSeconds != null && !isNaN(time.currentSeconds) - ? formatDisplay(time.currentSeconds, true) - : ''; + let stageTimer = formatDisplay(Math.abs(time.running), true); + if (time.running < 0) stageTimer = `-${stageTimer}`; return (
From 7c67d2e57d7c8cae3ad898c20f0ada78493b7339 Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Wed, 26 May 2021 22:33:14 +0200 Subject: [PATCH 13/14] update lib --- server/package.json | 2 +- server/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/server/package.json b/server/package.json index 45025a56a..8ecb67af8 100644 --- a/server/package.json +++ b/server/package.json @@ -8,7 +8,7 @@ "express-session": "~1.17.1", "lowdb": "^1.0.0", "nanoid": "^3.1.22", - "node-osc": "^6.0.1", + "node-osc": "6.0.2", "passport": "~0.4.1", "passport-local": "~1.0.0", "socket.io": "^4.0.0" diff --git a/server/yarn.lock b/server/yarn.lock index 4b7da8610..9778a0c2f 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -380,10 +380,10 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -node-osc@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/node-osc/-/node-osc-6.0.1.tgz#6f2c39996c64460435b678dc91c128d3a9711031" - integrity sha512-UZBQGH4vVTw3Ub5/xcnhlrhL6bpaYz3hhNjO4eup4tknyP5qOi2GVVnEmEn/qaTgTvs7SVyytj3OHg9JWRD4Aw== +node-osc@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/node-osc/-/node-osc-6.0.2.tgz#185d387928b186a84e8d0eebcae9e54a8bf50729" + integrity sha512-RW8PRLMh4H14veC5gZVUTcRkrk5pXd+b4vmitWL55c9ZI+5yEvMXkrokfnRH0u7DYveqw4h+uCPIUDifY/vjfA== dependencies: osc-min "^1.1.1" From 9314594051ca772aca0627cc9d1a5dd6fc46b51d Mon Sep 17 00:00:00 2001 From: cv <34649812+cpvalente@users.noreply.github.com> Date: Thu, 27 May 2021 15:01:34 +0200 Subject: [PATCH 14/14] handle error messages --- server/controllers/OscController.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/server/controllers/OscController.js b/server/controllers/OscController.js index dba6d9cc1..e4ddcb983 100644 --- a/server/controllers/OscController.js +++ b/server/controllers/OscController.js @@ -5,6 +5,9 @@ const initiateOSC = (config) => { console.log(`OSC Server is listening on port ${config.port}`); }); + // error + oscServer.on('error', console.error); + oscServer.on('message', function (msg) { // message should look like /ontime/{path}/{args} where // ontime: fixed message for app @@ -62,8 +65,8 @@ const initiateOSC = (config) => { console.log('calling goto with', args); try { let eventIndex = parseInt(args); - if (isNaN(eventIndex) || eventIndex <= 0) return; - global.timer.pause(); + if (isNaN(eventIndex) || eventIndex <= 0 || eventIndex == null) + return; global.timer.loadEvent(eventIndex - 1, undefined, true); } catch (error) { console.log('error calling goto: ', error); @@ -71,6 +74,7 @@ const initiateOSC = (config) => { break; case 'gotoid': console.log('calling gotoid with', args); + if (args == null) return; try { global.timer.loadEventById(args.toString().toLowerCase()); } catch (error) {