Merge branch 'master' into wip/migratedb

This commit is contained in:
cv
2021-05-28 14:46:54 +02:00
27 changed files with 284 additions and 110 deletions
+1 -1
View File
@@ -7,6 +7,6 @@ body,
html, html,
.App { .App {
margin: 0px auto; margin: 0px auto;
overflow: hidden; overflow: clip;
height: 100vh; height: 100vh;
} }
-9
View File
@@ -58,12 +58,3 @@ export const BatchOperation = atom(null, (get, set, payload) => {
localStorage.setItem(PATH, JSON.stringify(options)); 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 });
};
+1
View File
@@ -5,6 +5,7 @@ export const useFetch = (namespace, fn) => {
const { data, status, isError, refetch } = useQuery(namespace, fn, { const { data, status, isError, refetch } = useQuery(namespace, fn, {
refetchInterval: refetchIntervalMs, refetchInterval: refetchIntervalMs,
cacheTime: Infinity, cacheTime: Infinity,
notifyOnChangeProps: 'tracked',
}); });
return { data, status, isError, refetch }; return { data, status, isError, refetch };
@@ -10,8 +10,9 @@ export default function LockIconBtn(props) {
ref={ref} ref={ref}
size={props.size || 'xs'} size={props.size || 'xs'}
icon={<FiTarget />} icon={<FiTarget />}
colorScheme='pink' color={active ? 'pink.100' : 'pink.300'}
color={'pink.300'} borderColor={active ? undefined : 'pink.300'}
backgroundColor={active ? 'pink.300' : undefined}
variant={active ? 'solid' : 'outline'} variant={active ? 'solid' : 'outline'}
onClick={clickhandler} onClick={clickhandler}
_focus={{ boxShadow: 'none' }} _focus={{ boxShadow: 'none' }}
@@ -12,7 +12,6 @@ export default function RollIconBtn(props) {
width={120} width={120}
_focus={{ boxShadow: 'none' }} _focus={{ boxShadow: 'none' }}
{...rest} {...rest}
disabled
/> />
); );
} }
@@ -6,7 +6,7 @@ import { useInterval } from 'app/hooks/useInterval';
export default function Paginator(props) { export default function Paginator(props) {
const { events, selectedId } = props; const { events, selectedId } = props;
const LIMIT_PER_PAGE = props.limit || 8; 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 SCROLL_PAST = false;
const [numEvents, setNumEvents] = useState(0); const [numEvents, setNumEvents] = useState(0);
const [page, setPage] = useState([]); const [page, setPage] = useState([]);
+2 -2
View File
@@ -33,9 +33,9 @@ export default function EditableText(props) {
> >
<EditablePreview <EditablePreview
color={text === '' ? '#666' : 'inherit'} color={text === '' ? '#666' : 'inherit'}
maxWidth='20em' maxWidth='75%'
/> />
<EditableInput overflowX='hidden' maxWidth='20em' /> <EditableInput overflowX='hidden' maxWidth='75%' />
</Editable> </Editable>
</div> </div>
); );
+2 -8
View File
@@ -34,12 +34,12 @@ export default function EditableTimer(props) {
if (value === '') return false; if (value === '') return false;
// Time now and time submitedVal // Time now and time submitedVal
const original = stringFromMillis(time, false); const original = stringFromMillis(time + delay, false);
// check if time is different from before // check if time is different from before
if (value === original) return false; if (value === original) return false;
// conver to millis object // convert to millis object
const millis = timeStringToMillis(value, timeFormat); const millis = timeStringToMillis(value, timeFormat);
// validate with parent // validate with parent
@@ -51,14 +51,8 @@ export default function EditableTimer(props) {
return true; return true;
}; };
const showOriginal = () => {
setValue(stringFromMillis(time, false));
};
return ( return (
<Editable <Editable
onFocus={() => showOriginal}
onEdit={() => showOriginal}
onChange={(v) => setValue(v)} onChange={(v) => setValue(v)}
onSubmit={(v) => validateValue(v)} onSubmit={(v) => validateValue(v)}
value={value} value={value}
@@ -41,10 +41,7 @@ const Transport = ({ selectedId, playbackControl }) => {
<div className={style.playbackContainer}> <div className={style.playbackContainer}>
<PrevIconBtn clickhandler={() => playbackControl('previous')} /> <PrevIconBtn clickhandler={() => playbackControl('previous')} />
<NextIconBtn clickhandler={() => playbackControl('next')} /> <NextIconBtn clickhandler={() => playbackControl('next')} />
<UnloadIconBtn <UnloadIconBtn clickhandler={() => playbackControl('unload')} />
clickhandler={() => playbackControl('unload')}
disabled={!selectedId}
/>
<ReloadIconButton <ReloadIconButton
clickhandler={() => playbackControl('reload')} clickhandler={() => playbackControl('reload')}
disabled={!selectedId} disabled={!selectedId}
@@ -90,6 +90,7 @@ export default function PlaybackControl() {
<div className={style.mainContainer}> <div className={style.mainContainer}>
<PlaybackTimer <PlaybackTimer
timer={timer} timer={timer}
playback={playback}
handleIncrement={(amount) => socket.emit('increment-timer', amount)} handleIncrement={(amount) => socket.emit('increment-timer', amount)}
/> />
<PlaybackButtons <PlaybackButtons
@@ -35,18 +35,19 @@
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-around; justify-content: space-evenly;
} }
.indRoll, .indRoll,
.indDelay, .indDelay,
.indNegative { .indNegative {
background-color: rgba(0, 0, 0, 0.05); background-color: rgba(0, 0, 0, 0.05);
margin: 0 auto;
} }
.indRoll, .indRoll,
.indRollActive,
.indDelay { .indDelay {
margin: 0 auto;
border-radius: 50%; border-radius: 50%;
width: 0.8em; width: 0.8em;
height: 0.8em; height: 0.8em;
@@ -60,7 +61,7 @@
.indNegativeActive { .indNegativeActive {
margin: 0 auto; margin: 0 auto;
width: 90%; width: 90%;
height: 0.3em height: 0.3em;
} }
.indNegativeActive { .indNegativeActive {
+26 -8
View File
@@ -8,16 +8,18 @@ const areEqual = (prevProps, nextProps) => {
return ( return (
prevProps.timer.running === nextProps.timer.running && prevProps.timer.running === nextProps.timer.running &&
prevProps.timer.expectedFinish === nextProps.timer.expectedFinish && 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 started = stringFromMillis(timer.startedAt, true);
const finish = stringFromMillis(timer.expectedFinish, true); const finish = stringFromMillis(timer.expectedFinish, true);
const isNegative = timer.running < 0; const isNegative = timer.running < 0;
const isDelayed = false; const isDelayed = false;
const isRolling = false; const isRolling = playback === 'roll';
const incrementProps = { const incrementProps = {
size: 'sm', size: 'sm',
@@ -31,7 +33,7 @@ const PlaybackTimer = ({ timer, handleIncrement }) => {
<> <>
<div className={style.timeContainer}> <div className={style.timeContainer}>
<div className={style.indicators}> <div className={style.indicators}>
<div className={style.indRoll} /> <div className={isRolling ? style.indRollActive : style.indRoll} />
<div <div
className={isNegative ? style.indNegativeActive : style.indNegative} className={isNegative ? style.indNegativeActive : style.indNegative}
/> />
@@ -49,16 +51,32 @@ const PlaybackTimer = ({ timer, handleIncrement }) => {
<span className={style.time}>{finish}</span> <span className={style.time}>{finish}</span>
</div> </div>
<div className={style.btn}> <div className={style.btn}>
<Button {...incrementProps} onClick={() => handleIncrement(-1)}> <Button
{...incrementProps}
disabled={isRolling}
onClick={() => handleIncrement(-1)}
>
-1 -1
</Button> </Button>
<Button {...incrementProps} onClick={() => handleIncrement(1)}> <Button
{...incrementProps}
disabled={isRolling}
onClick={() => handleIncrement(1)}
>
+1 +1
</Button> </Button>
<Button {...incrementProps} onClick={() => handleIncrement(-5)}> <Button
{...incrementProps}
disabled={isRolling}
onClick={() => handleIncrement(-5)}
>
-5 -5
</Button> </Button>
<Button {...incrementProps} onClick={() => handleIncrement(5)}> <Button
{...incrementProps}
disabled={isRolling}
onClick={() => handleIncrement(5)}
>
+5 +5
</Button> </Button>
</div> </div>
@@ -18,11 +18,12 @@
/* 2/3 window, hide previews */ /* 2/3 window, hide previews */
@media (max-width: 1250px) and (min-height: 700px) { @media (max-width: 1250px) and (min-height: 700px) {
.mainContainer { .mainContainer {
height: 100%;
grid-template-rows: 1fr 1fr; grid-template-rows: 1fr 1fr;
grid-template-columns: 48em 1fr 1fr; grid-template-columns: 48em 1fr 1fr;
grid-template-areas: /* grid-template-areas:
'even play sett' 'even play sett'
'even mess sett'; 'even mess sett'; */
} }
.info { .info {
@@ -40,6 +41,11 @@
'play'; 'play';
} }
.messages,
.playback {
min-width: 31em;
}
.editor, .editor,
.info, .info,
.settings { .settings {
@@ -17,7 +17,7 @@ export default function ActionButtons(props) {
aria-label='Options' aria-label='Options'
size='xs' size='xs'
icon={<FiZap />} icon={<FiZap />}
_expanded={{ bg: 'pink.300', color: 'white' }} _expanded={{ bg: 'orange.300', color: 'white' }}
_focus={{ boxShadow: 'none' }} _focus={{ boxShadow: 'none' }}
backgroundColor={'orange.200'} backgroundColor={'orange.200'}
color={'orange.500'} color={'orange.500'}
@@ -14,7 +14,8 @@ import { SelectCollapse, HandleCollapse } from 'app/context/collapseAtom';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
const ExpandedBlock = (props) => { 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; const oscid = data.id.length > 4 ? '...' : data.id;
@@ -80,7 +81,9 @@ const ExpandedBlock = (props) => {
actionHandler('update', { field: 'note', value: v }) actionHandler('update', { field: 'note', value: v })
} }
/> />
<span className={style.oscLabel}>{`OSC ID: ${oscid}`}</span> <span className={style.oscLabel}>
{`/ontime/goto ${eventIndex + 1} << OSC >> /ontime/gotoid ${oscid}`}
</span>
</div> </div>
<Icon <Icon
className={style.more} className={style.more}
@@ -156,7 +159,7 @@ const CollapsedBlock = (props) => {
}; };
export default function EventBlock(props) { 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)); // const [collapsed, setCollapsed] = useState(checkLocalStorage(data.id));
@@ -200,6 +203,7 @@ export default function EventBlock(props) {
) : ( ) : (
<ExpandedBlock <ExpandedBlock
provided={provided} provided={provided}
eventIndex={eventIndex}
data={data} data={data}
next={props.next} next={props.next}
delay={delay} delay={delay}
+26 -13
View File
@@ -27,7 +27,7 @@ export default function EventList(props) {
}, },
'Alt+ArrowUp': () => { 'Alt+ArrowUp': () => {
if (cursor == null) setCursor(0); if (cursor == null) setCursor(0);
else if (cursor >= 0) setCursor(cursor - 1); else if (cursor > 0) setCursor(cursor - 1);
}, },
'Alt+KeyE': (event) => { 'Alt+KeyE': (event) => {
event.preventDefault(); event.preventDefault();
@@ -49,7 +49,7 @@ export default function EventList(props) {
return () => { return () => {
unsubscribe(); unsubscribe();
}; };
}, [cursor, events.length, eventsHandler]); }, [cursor, events, eventsHandler]);
// handle incoming messages // handle incoming messages
useEffect(() => { useEffect(() => {
@@ -62,7 +62,6 @@ export default function EventList(props) {
// Handle playstate // Handle playstate
socket.on('selected', (data) => { socket.on('selected', (data) => {
setSelected(data); setSelected(data);
console.log('debug cursor setted', data);
}); });
socket.on('next-id', (data) => { socket.on('next-id', (data) => {
setNext(data); setNext(data);
@@ -80,13 +79,20 @@ export default function EventList(props) {
if (cursorSettings !== 'locked' || selected == null) return; if (cursorSettings !== 'locked' || selected == null) return;
if (selected.index == null) return; if (selected.index == null) return;
setCursor(selected.index); let eventIndex = -1;
}, [selected, cursorSettings]); 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 // attach scroll to cursor
useEffect(() => { useEffect(() => {
if (cursor == null || cursorRef.current == null) return; if (cursor == null || cursorRef.current == null) return;
console.log('debug cursor scrolling');
cursorRef.current.scrollIntoView({ cursorRef.current.scrollIntoView({
behavior: 'smooth', behavior: 'smooth',
@@ -117,8 +123,7 @@ export default function EventList(props) {
console.log('EventList: events in event list', events); console.log('EventList: events in event list', events);
let cumulativeDelay = 0; let cumulativeDelay = 0;
let eventIndex = -1;
console.log('debug selected', selected);
return ( return (
<div className={style.eventContainer}> <div className={style.eventContainer}>
@@ -131,20 +136,28 @@ export default function EventList(props) {
ref={provided.innerRef} ref={provided.innerRef}
> >
{events.map((e, index) => { {events.map((e, index) => {
let isCursor = cursor === index; if (index === 0) {
if (index === 0) cumulativeDelay = 0; cumulativeDelay = 0;
eventIndex = -1;
}
if (e.type === 'delay' && e.duration != null) { if (e.type === 'delay' && e.duration != null) {
cumulativeDelay += e.duration; cumulativeDelay += e.duration;
} else if (e.type === 'block') cumulativeDelay = 0; } else if (e.type === 'block') {
cumulativeDelay = 0;
} else if (e.type === 'event') {
eventIndex++;
}
return ( return (
<div <div
ref={isCursor ? cursorRef : undefined} ref={cursor === index ? cursorRef : undefined}
key={e.id} key={e.id}
className={isCursor ? style.cursor : undefined} className={cursor === index ? style.cursor : undefined}
> >
<EventListItem <EventListItem
type={e.type} type={e.type}
index={index} index={index}
eventIndex={eventIndex}
data={e} data={e}
selected={selected?.id === e.id} selected={selected?.id === e.id}
next={next === e.id} next={next === e.id}
@@ -18,6 +18,7 @@ const EventListItem = (props) => {
const { const {
type, type,
index, index,
eventIndex,
data, data,
selected, selected,
next, next,
@@ -71,6 +72,7 @@ const EventListItem = (props) => {
return ( return (
<EventBlock <EventBlock
index={index} index={index}
eventIndex={eventIndex}
data={data} data={data}
selected={selected} selected={selected}
next={next} next={next}
@@ -23,7 +23,7 @@ export default function MenuActionButtons(props) {
aria-label='Options' aria-label='Options'
size={props.size || 'xs'} size={props.size || 'xs'}
icon={<FiZap />} icon={<FiZap />}
_expanded={{ bg: 'pink.300', color: 'white' }} _expanded={{ bg: 'orange.300', color: 'white' }}
_focus={{ boxShadow: 'none' }} _focus={{ boxShadow: 'none' }}
backgroundColor={'orange.200'} backgroundColor={'orange.200'}
color={'orange.500'} color={'orange.500'}
+2 -2
View File
@@ -37,7 +37,7 @@ const withSocket = (Component) => {
}); });
const [timer, setTimer] = useState({ const [timer, setTimer] = useState({
clock: null, clock: null,
currentSeconds: null, running: null,
startedAt: null, startedAt: null,
expectedFinish: null, expectedFinish: null,
}); });
@@ -221,7 +221,7 @@ const withSocket = (Component) => {
// get clock string // get clock string
const timeManager = { const timeManager = {
...timer, ...timer,
finished: timer.running <= 0 && timer.startedAt, finished: playback === 'start' && timer.running <= 0 && timer.startedAt,
clock: stringFromMillis(timer.clock), clock: stringFromMillis(timer.clock),
playstate: playback, playstate: playback,
}; };
@@ -42,7 +42,7 @@ export default function StageManager(props) {
// Format messages // Format messages
const showPubl = publ.text !== '' && publ.visible; const showPubl = publ.text !== '' && publ.visible;
let stageTimer = formatDisplay(Math.abs(time.running), true); let stageTimer = formatDisplay(Math.abs(time.running), true);
if (time.running < 0) stageTimer = '-' + stageTimer; if (time.running < 0) stageTimer = `-${stageTimer}`;
// motion // motion
const titleVariants = { const titleVariants = {
@@ -14,10 +14,9 @@ export default function PresenterView(props) {
document.title = 'ontime - Speaker Screen'; document.title = 'ontime - Speaker Screen';
}, []); }, []);
const showOverlay = pres.text !== '' && pres.visible; const showOverlay = pres.text !== '' && pres.visible;
const isPlaying = time.playstate === 'start'; const isPlaying = time.playstate !== 'pause';
const normalisedTime = Math.max(time.running, 0);
// motion // motion
const titleVariants = { const titleVariants = {
@@ -61,7 +60,7 @@ export default function PresenterView(props) {
<div className={style.finished}>TIME UP</div> <div className={style.finished}>TIME UP</div>
) : ( ) : (
<div className={isPlaying ? style.countdown : style.countdownPaused}> <div className={isPlaying ? style.countdown : style.countdownPaused}>
<Countdown time={time.currentSeconds} hideZeroHours /> <Countdown time={normalisedTime} hideZeroHours />
</div> </div>
)} )}
</div> </div>
@@ -73,7 +72,7 @@ export default function PresenterView(props) {
} }
> >
<MyProgressBar <MyProgressBar
now={time.currentSeconds} now={normalisedTime}
complete={time.durationSeconds} complete={time.durationSeconds}
showElapsed showElapsed
/> />
@@ -51,11 +51,8 @@ export default function Pip(props) {
// Format messages // Format messages
const showInfo = const showInfo =
general.backstageInfo !== '' && general.backstageInfo != null; general.backstageInfo !== '' && general.backstageInfo != null;
let stageTimer = formatDisplay(Math.abs(time.running), true);
const stageTimer = if (time.running < 0) stageTimer = `-${stageTimer}`;
time.currentSeconds != null && !isNaN(time.currentSeconds)
? formatDisplay(time.currentSeconds, true)
: '';
return ( return (
<div className={style.container__gray}> <div className={style.container__gray}>
+1 -1
View File
@@ -10,7 +10,7 @@
"lowdb": "2.1.0", "lowdb": "2.1.0",
"multer": "^1.4.2", "multer": "^1.4.2",
"nanoid": "^3.1.22", "nanoid": "^3.1.22",
"node-osc": "^6.0.1", "node-osc": "6.0.2",
"passport": "~0.4.1", "passport": "~0.4.1",
"passport-local": "~1.0.0", "passport-local": "~1.0.0",
"socket.io": "^4.0.0" "socket.io": "^4.0.0"
+168 -29
View File
@@ -109,8 +109,29 @@ export class EventTimer extends Timer {
update() { update() {
// if there is nothing selected, no nothing // if there is nothing selected, no nothing
if (this.selectedEventId == null) return; if (this.selectedEventId == null && this.state !== 'roll') return;
super.update();
// only implement roll here
if (this.state !== 'roll') {
super.update();
return;
}
// get current time
const now = this._getCurrentTime();
this.clock = now;
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;
}
} }
start() { start() {
@@ -140,10 +161,11 @@ export class EventTimer extends Timer {
else if (payload === 'next') this.next(); else if (payload === 'next') this.next();
else if (payload === 'reload') this.reload(); else if (payload === 'reload') this.reload();
else if (payload === 'unload') this.unload(); else if (payload === 'unload') this.unload();
else if (payload === 'roll') this.roll();
// Not yet implemented // TODO: Cleanup
// else if (payload === 'roll') this.roll(); // here tdo this.broadcastState;
// remove broadcast from functions
this.broadcastThis('playstate', this.state); this.broadcastThis('playstate', this.state);
this.broadcastThis('selected-id', this.selectedEventId); this.broadcastThis('selected-id', this.selectedEventId);
this.broadcastThis('titles', this.titles); this.broadcastThis('titles', this.titles);
@@ -472,7 +494,7 @@ export class EventTimer extends Timer {
if (eventIndex === -1) return; if (eventIndex === -1) return;
this.pause(); this.pause();
this.loadEvent(eventIndex, true, true); this.loadEvent(eventIndex, 'load', true);
} }
// Loads a given event // Loads a given event
@@ -522,18 +544,12 @@ export class EventTimer extends Timer {
if (e == null) return; if (e == null) return;
// private title is always current // 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 // check if current is also public
if (e.isPublic) { if (e.isPublic) {
this.titlesPublic.titleNow = e.title; this._loadThisTitles(e, 'now');
this.titlesPublic.subtitleNow = e.subtitle;
this.titlesPublic.presenterNow = e.presenter;
this.selectedPublicEventId = e.id;
} else { } else {
this._loadThisTitles(e, 'now-private');
// assume there is no public event // assume there is no public event
this.titlesPublic.titleNow = null; this.titlesPublic.titleNow = null;
this.titlesPublic.subtitleNow = null; this.titlesPublic.subtitleNow = null;
@@ -549,16 +565,77 @@ export class EventTimer extends Timer {
this._eventlist[i].type === 'event' && this._eventlist[i].type === 'event' &&
this._eventlist[i].isPublic this._eventlist[i].isPublic
) { ) {
this.titlesPublic.titleNow = this._eventlist[i].title; this._loadThisTitles(this._eventlist[i], 'now-public');
this.titlesPublic.subtitleNow = this._eventlist[i].subtitle;
this.titlesPublic.presenterNow = this._eventlist[i].presenter;
this.selectedPublicEventId = this._eventlist[i].id;
break; break;
} }
} }
} }
} }
_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':
// 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:
break;
}
}
_loadTitlesNext() { _loadTitlesNext() {
// maybe there is nothing to load // maybe there is nothing to load
if (this.selectedEventIndex == null) return; if (this.selectedEventIndex == null) return;
@@ -583,19 +660,13 @@ export class EventTimer extends Timer {
if (this._eventlist[i].type === 'event') { if (this._eventlist[i].type === 'event') {
// if we have not set private // if we have not set private
if (!nextPrivate) { if (!nextPrivate) {
this.titles.titleNext = this._eventlist[i].title; this._loadThisTitles(this._eventlist[i], 'next-private');
this.titles.subtitleNext = this._eventlist[i].subtitle;
this.titles.presenterNext = this._eventlist[i].presenter;
this.nextEventId = this._eventlist[i].id;
nextPrivate = true; nextPrivate = true;
} }
// if event is public // if event is public
if (this._eventlist[i].isPublic) { if (this._eventlist[i].isPublic) {
this.titlesPublic.titleNext = this._eventlist[i].title; this._loadThisTitles(this._eventlist[i], 'next-public');
this.titlesPublic.subtitleNext = this._eventlist[i].subtitle;
this.titlesPublic.presenterNext = this._eventlist[i].presenter;
this.nextPublicEventId = this._eventlist[i].id;
nextPublic = true; nextPublic = true;
} }
} }
@@ -642,6 +713,7 @@ export class EventTimer extends Timer {
state = ${this.state} state = ${this.state}
current = ${this.current} current = ${this.current}
duration = ${this.duration} duration = ${this.duration}
secondaryTimer = ${this.secondaryTimer}
Events Events
------------------------------ ------------------------------
@@ -730,10 +802,77 @@ export class EventTimer extends Timer {
this.broadcastState(); this.broadcastState();
} }
rollLoad() {
const now = this._getCurrentTime();
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 (!foundNow) {
if (e.timeStart <= now && now < e.timeEnd) {
// set flag
foundNow = true;
// 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();
// 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;
}
}
}
roll() { roll() {
console.log('roll: not yet implemented'); // do we need to change
return false; if (this.state === 'roll') return;
// load into event
this.rollLoad();
// set state
this.state = 'roll'; this.state = 'roll';
this.broadcastState();
} }
previous() { previous() {
+8 -2
View File
@@ -8,6 +8,7 @@ export class Timer {
clock = null; clock = null;
duration = null; duration = null;
current = null; current = null;
secondaryTimer = null;
_finishAt = null; _finishAt = null;
_finishedAt = null; _finishedAt = null;
_startedAt = null; _startedAt = null;
@@ -50,6 +51,9 @@ export class Timer {
// check playstate // check playstate
switch (this.state) { switch (this.state) {
case 'start': case 'start':
// ensure we have a start time
if (this._startedAt == null) this._startedAt = now;
// update current timer // update current timer
this.current = this.current =
this._startedAt + this.duration + this._pausedTotal - now; this._startedAt + this.duration + this._pausedTotal - now;
@@ -110,8 +114,10 @@ export class Timer {
); );
} }
_resetTimers() { _resetTimers(total = false) {
if (total) this.duration = null;
this.current = this.duration; this.current = this.duration;
this.secondaryTimer = null;
this._finishAt = null; this._finishAt = null;
this._finishedAt = null; this._finishedAt = null;
this._startedAt = null; this._startedAt = null;
@@ -132,7 +138,7 @@ export class Timer {
return { return {
clock: this.clock, clock: this.clock,
running: Timer.toSeconds(this.current), running: Timer.toSeconds(this.current),
currentSeconds: Timer.toSeconds(Math.max(this.current, 0)), secondary: Timer.toSeconds(this.secondaryTimer),
durationSeconds: Timer.toSeconds(this.duration), durationSeconds: Timer.toSeconds(this.duration),
expectedFinish: this._getExpectedFinish(), expectedFinish: this._getExpectedFinish(),
startedAt: this._startedAt, startedAt: this._startedAt,
+7 -2
View File
@@ -5,6 +5,9 @@ export const initiateOSC = (config) => {
console.log(`OSC Server is listening on port ${config.port}`); console.log(`OSC Server is listening on port ${config.port}`);
}); });
// error
oscServer.on('error', console.error);
oscServer.on('message', function (msg) { oscServer.on('message', function (msg) {
// message should look like /ontime/{path}/{args} where // message should look like /ontime/{path}/{args} where
// ontime: fixed message for app // ontime: fixed message for app
@@ -62,7 +65,8 @@ export const initiateOSC = (config) => {
console.log('calling goto with', args); console.log('calling goto with', args);
try { try {
let eventIndex = parseInt(args); let eventIndex = parseInt(args);
if (isNaN(eventIndex) || eventIndex <= 0) return; if (isNaN(eventIndex) || eventIndex <= 0 || eventIndex == null)
return;
global.timer.loadEvent(eventIndex - 1, undefined, true); global.timer.loadEvent(eventIndex - 1, undefined, true);
} catch (error) { } catch (error) {
console.log('error calling goto: ', error); console.log('error calling goto: ', error);
@@ -70,8 +74,9 @@ export const initiateOSC = (config) => {
break; break;
case 'gotoid': case 'gotoid':
console.log('calling gotoid with', args); console.log('calling gotoid with', args);
if (args == null) return;
try { try {
global.timer.loadEventById(args.toLowerCase()); global.timer.loadEventById(args.toString().toLowerCase());
} catch (error) { } catch (error) {
console.log('error calling goto: ', error); console.log('error calling goto: ', error);
} }
+4 -4
View File
@@ -438,10 +438,10 @@ negotiator@0.6.2:
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
node-osc@^6.0.1: node-osc@6.0.2:
version "6.0.1" version "6.0.2"
resolved "https://registry.yarnpkg.com/node-osc/-/node-osc-6.0.1.tgz#6f2c39996c64460435b678dc91c128d3a9711031" resolved "https://registry.yarnpkg.com/node-osc/-/node-osc-6.0.2.tgz#185d387928b186a84e8d0eebcae9e54a8bf50729"
integrity sha512-UZBQGH4vVTw3Ub5/xcnhlrhL6bpaYz3hhNjO4eup4tknyP5qOi2GVVnEmEn/qaTgTvs7SVyytj3OHg9JWRD4Aw== integrity sha512-RW8PRLMh4H14veC5gZVUTcRkrk5pXd+b4vmitWL55c9ZI+5yEvMXkrokfnRH0u7DYveqw4h+uCPIUDifY/vjfA==
dependencies: dependencies:
osc-min "^1.1.1" osc-min "^1.1.1"