mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-10 16:49:41 +00:00
refactor: cleanup store (#727)
* refactor: isolate clock * refactor: isolate private * refactor: remove duplicate * chore: rename loaded > runtime * fix: handle no events loaded
This commit is contained in:
@@ -3,7 +3,7 @@ import React from 'react';
|
|||||||
// skipcq: JS-C1003 - sentry does not expose itself as an ES Module.
|
// skipcq: JS-C1003 - sentry does not expose itself as an ES Module.
|
||||||
import * as Sentry from '@sentry/react';
|
import * as Sentry from '@sentry/react';
|
||||||
|
|
||||||
import { runtime } from '@/common/stores/runtime';
|
import { runtimeStore } from '@/common/stores/runtime';
|
||||||
import { hasConnected, reconnectAttempts, shouldReconnect } from '@/common/utils/socket';
|
import { hasConnected, reconnectAttempts, shouldReconnect } from '@/common/utils/socket';
|
||||||
|
|
||||||
import style from './ErrorBoundary.module.scss';
|
import style from './ErrorBoundary.module.scss';
|
||||||
@@ -29,7 +29,7 @@ class ErrorBoundary extends React.Component {
|
|||||||
|
|
||||||
Sentry.withScope((scope) => {
|
Sentry.withScope((scope) => {
|
||||||
scope.setExtras('error', error);
|
scope.setExtras('error', error);
|
||||||
scope.setExtras('store', runtime.getState());
|
scope.setExtras('store', runtimeStore.getState());
|
||||||
scope.setExtras('hasSocket', { hasConnected, shouldReconnect, reconnectAttempts });
|
scope.setExtras('hasSocket', { hasConnected, shouldReconnect, reconnectAttempts });
|
||||||
const eventId = Sentry.captureException(error);
|
const eventId = Sentry.captureException(error);
|
||||||
this.setState({ eventId, info });
|
this.setState({ eventId, info });
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
|
import { MaybeNumber } from 'ontime-types';
|
||||||
|
|
||||||
import { clamp } from '../../utils/math';
|
import { clamp } from '../../utils/math';
|
||||||
|
|
||||||
import './MultiPartProgressBar.scss';
|
import './MultiPartProgressBar.scss';
|
||||||
|
|
||||||
interface MultiPartProgressBar {
|
interface MultiPartProgressBar {
|
||||||
now: number | null;
|
now: MaybeNumber;
|
||||||
complete: number;
|
complete: number;
|
||||||
normalColor: string;
|
normalColor: string;
|
||||||
warning?: number | null;
|
warning?: MaybeNumber;
|
||||||
warningColor: string;
|
warningColor: string;
|
||||||
danger?: number | null;
|
danger?: MaybeNumber;
|
||||||
dangerColor: string;
|
dangerColor: string;
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import { socketSendJson } from '../utils/socket';
|
|||||||
|
|
||||||
export const useRundownEditor = () => {
|
export const useRundownEditor = () => {
|
||||||
const featureSelector = (state: RuntimeStore) => ({
|
const featureSelector = (state: RuntimeStore) => ({
|
||||||
playback: state.playback,
|
playback: state.timer.playback,
|
||||||
selectedEventId: state.loaded.selectedEventId,
|
selectedEventId: state.eventNow?.id ?? null,
|
||||||
nextEventId: state.loaded.nextEventId,
|
nextEventId: state.eventNext?.id ?? null,
|
||||||
});
|
});
|
||||||
|
|
||||||
return useRuntimeStore(featureSelector);
|
return useRuntimeStore(featureSelector);
|
||||||
@@ -15,8 +15,8 @@ export const useRundownEditor = () => {
|
|||||||
|
|
||||||
export const useOperator = () => {
|
export const useOperator = () => {
|
||||||
const featureSelector = (state: RuntimeStore) => ({
|
const featureSelector = (state: RuntimeStore) => ({
|
||||||
playback: state.playback,
|
playback: state.timer.playback,
|
||||||
selectedEventId: state.loaded.selectedEventId,
|
selectedEventId: state.eventNow?.id ?? null,
|
||||||
});
|
});
|
||||||
|
|
||||||
return useRuntimeStore(featureSelector);
|
return useRuntimeStore(featureSelector);
|
||||||
@@ -50,9 +50,9 @@ export const setMessage = {
|
|||||||
|
|
||||||
export const usePlaybackControl = () => {
|
export const usePlaybackControl = () => {
|
||||||
const featureSelector = (state: RuntimeStore) => ({
|
const featureSelector = (state: RuntimeStore) => ({
|
||||||
playback: state.playback,
|
playback: state.timer.playback,
|
||||||
selectedEventIndex: state.loaded.selectedEventIndex,
|
selectedEventIndex: state.runtime.selectedEventIndex,
|
||||||
numEvents: state.loaded.numEvents,
|
numEvents: state.runtime.numEvents,
|
||||||
});
|
});
|
||||||
|
|
||||||
return useRuntimeStore(featureSelector);
|
return useRuntimeStore(featureSelector);
|
||||||
@@ -80,12 +80,24 @@ export const setPlayback = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useInfoPanel = () => {
|
||||||
|
const featureSelector = (state: RuntimeStore) => ({
|
||||||
|
eventNow: state.eventNow,
|
||||||
|
eventNext: state.eventNext,
|
||||||
|
playback: state.timer.playback,
|
||||||
|
selectedEventIndex: state.runtime.selectedEventIndex,
|
||||||
|
numEvents: state.runtime.numEvents,
|
||||||
|
});
|
||||||
|
|
||||||
|
return useRuntimeStore(featureSelector);
|
||||||
|
};
|
||||||
|
|
||||||
export const useCuesheet = () => {
|
export const useCuesheet = () => {
|
||||||
const featureSelector = (state: RuntimeStore) => ({
|
const featureSelector = (state: RuntimeStore) => ({
|
||||||
playback: state.playback,
|
playback: state.timer.playback,
|
||||||
selectedEventId: state.loaded.selectedEventId,
|
selectedEventId: state.eventNow?.id ?? null,
|
||||||
selectedEventIndex: state.loaded.selectedEventIndex,
|
selectedEventIndex: state.runtime.selectedEventIndex,
|
||||||
numEvents: state.loaded.numEvents,
|
numEvents: state.runtime.numEvents,
|
||||||
titleNow: state.eventNow?.title || '',
|
titleNow: state.eventNow?.title || '',
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -107,14 +119,33 @@ export const useTimer = () => {
|
|||||||
return useRuntimeStore(featureSelector);
|
return useRuntimeStore(featureSelector);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useClock = () => {
|
||||||
|
const featureSelector = (state: RuntimeStore) => ({
|
||||||
|
clock: state.clock,
|
||||||
|
});
|
||||||
|
return useRuntimeStore(featureSelector);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Used by the progress bar components */
|
||||||
|
export const useProgressData = () => {
|
||||||
|
const featureSelector = (state: RuntimeStore) => ({
|
||||||
|
addedTime: state.timer.addedTime,
|
||||||
|
current: state.timer.current,
|
||||||
|
duration: state.timer.duration,
|
||||||
|
timeWarning: state.eventNow?.timeWarning ?? null,
|
||||||
|
timeDanger: state.eventNow?.timeDanger ?? null,
|
||||||
|
});
|
||||||
|
return useRuntimeStore(featureSelector);
|
||||||
|
};
|
||||||
|
|
||||||
export const setClientName = (newName: string) => socketSendJson('set-client-name', newName);
|
export const setClientName = (newName: string) => socketSendJson('set-client-name', newName);
|
||||||
|
|
||||||
export const useRuntimeOverview = () => {
|
export const useRuntimeOverview = () => {
|
||||||
const featureSelector = (state: RuntimeStore) => ({
|
const featureSelector = (state: RuntimeStore) => ({
|
||||||
playback: state.playback,
|
playback: state.timer.playback,
|
||||||
clock: state.timer.clock,
|
clock: state.clock,
|
||||||
numEvents: state.loaded.numEvents,
|
selectedEventIndex: state.runtime.selectedEventIndex,
|
||||||
selectedEventIndex: state.loaded.selectedEventIndex,
|
numEvents: state.runtime.numEvents,
|
||||||
});
|
});
|
||||||
|
|
||||||
return useRuntimeStore(featureSelector);
|
return useRuntimeStore(featureSelector);
|
||||||
|
|||||||
@@ -1,21 +1,19 @@
|
|||||||
import { Playback, TimerType } from 'ontime-types';
|
import { MaybeNumber, Playback, TimerType } from 'ontime-types';
|
||||||
|
|
||||||
export type TimeManagerType = {
|
// first set extends TimerState
|
||||||
clock: number;
|
export type ViewExtendedTimer = {
|
||||||
current: null | number;
|
|
||||||
elapsed: null | number;
|
|
||||||
duration: null | number;
|
|
||||||
timerBehaviour?: string;
|
|
||||||
timerType: TimerType;
|
|
||||||
expectedFinish: null | number;
|
|
||||||
addedTime: number;
|
addedTime: number;
|
||||||
startedAt: null | number;
|
current: MaybeNumber;
|
||||||
finishedAt: null | number;
|
duration: MaybeNumber;
|
||||||
secondaryTimer: null | number;
|
elapsed: MaybeNumber;
|
||||||
|
expectedFinish: MaybeNumber;
|
||||||
finished: boolean;
|
finishedAt: MaybeNumber;
|
||||||
playback: Playback;
|
playback: Playback;
|
||||||
|
secondaryTimer: MaybeNumber;
|
||||||
|
startedAt: MaybeNumber;
|
||||||
|
|
||||||
timeWarning: number | null;
|
clock: number;
|
||||||
timeDanger: number | null;
|
timeDanger: MaybeNumber;
|
||||||
|
timeWarning: MaybeNumber;
|
||||||
|
timerType: TimerType;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,22 +3,19 @@ import { Playback, RuntimeStore } from 'ontime-types';
|
|||||||
import { createWithEqualityFn, useStoreWithEqualityFn } from 'zustand/traditional';
|
import { createWithEqualityFn, useStoreWithEqualityFn } from 'zustand/traditional';
|
||||||
|
|
||||||
export const runtimeStorePlaceholder: RuntimeStore = {
|
export const runtimeStorePlaceholder: RuntimeStore = {
|
||||||
|
clock: 0,
|
||||||
timer: {
|
timer: {
|
||||||
clock: 0,
|
addedTime: 0,
|
||||||
current: null,
|
current: null,
|
||||||
|
duration: null,
|
||||||
elapsed: null,
|
elapsed: null,
|
||||||
expectedFinish: null,
|
expectedFinish: null,
|
||||||
addedTime: 0,
|
|
||||||
startedAt: null,
|
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
|
playback: Playback.Stop,
|
||||||
secondaryTimer: null,
|
secondaryTimer: null,
|
||||||
duration: null,
|
startedAt: null,
|
||||||
timerType: null,
|
|
||||||
endAction: null,
|
|
||||||
timeWarning: null,
|
|
||||||
timeDanger: null,
|
|
||||||
},
|
},
|
||||||
playback: Playback.Stop,
|
onAir: false,
|
||||||
message: {
|
message: {
|
||||||
timer: {
|
timer: {
|
||||||
text: '',
|
text: '',
|
||||||
@@ -39,14 +36,9 @@ export const runtimeStorePlaceholder: RuntimeStore = {
|
|||||||
visible: false,
|
visible: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
onAir: false,
|
runtime: {
|
||||||
loaded: {
|
|
||||||
numEvents: 0,
|
numEvents: 0,
|
||||||
selectedEventIndex: null,
|
selectedEventIndex: null,
|
||||||
selectedEventId: null,
|
|
||||||
selectedPublicEventId: null,
|
|
||||||
nextEventId: null,
|
|
||||||
nextPublicEventId: null,
|
|
||||||
},
|
},
|
||||||
eventNow: null,
|
eventNow: null,
|
||||||
eventNext: null,
|
eventNext: null,
|
||||||
@@ -56,7 +48,7 @@ export const runtimeStorePlaceholder: RuntimeStore = {
|
|||||||
|
|
||||||
const deepCompare = <T>(a: T, b: T) => isEqual(a, b);
|
const deepCompare = <T>(a: T, b: T) => isEqual(a, b);
|
||||||
|
|
||||||
export const runtime = createWithEqualityFn<RuntimeStore>(
|
export const runtimeStore = createWithEqualityFn<RuntimeStore>(
|
||||||
() => ({
|
() => ({
|
||||||
...runtimeStorePlaceholder,
|
...runtimeStorePlaceholder,
|
||||||
}),
|
}),
|
||||||
@@ -64,4 +56,4 @@ export const runtime = createWithEqualityFn<RuntimeStore>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const useRuntimeStore = <T>(selector: (state: RuntimeStore) => T) =>
|
export const useRuntimeStore = <T>(selector: (state: RuntimeStore) => T) =>
|
||||||
useStoreWithEqualityFn(runtime, selector, deepCompare);
|
useStoreWithEqualityFn(runtimeStore, selector, deepCompare);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { isProduction, RUNTIME, websocketUrl } from '../api/apiConstants';
|
|||||||
import { ontimeQueryClient } from '../queryClient';
|
import { ontimeQueryClient } from '../queryClient';
|
||||||
import { socketClientName } from '../stores/connectionName';
|
import { socketClientName } from '../stores/connectionName';
|
||||||
import { addLog } from '../stores/logger';
|
import { addLog } from '../stores/logger';
|
||||||
import { runtime } from '../stores/runtime';
|
import { runtimeStore } from '../stores/runtime';
|
||||||
|
|
||||||
export let websocket: WebSocket | null = null;
|
export let websocket: WebSocket | null = null;
|
||||||
let reconnectTimeout: NodeJS.Timeout | null = null;
|
let reconnectTimeout: NodeJS.Timeout | null = null;
|
||||||
@@ -63,40 +63,40 @@ export const connectSocket = (preferredClientName?: string) => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'ontime': {
|
case 'ontime': {
|
||||||
runtime.setState(payload as RuntimeStore);
|
runtimeStore.setState(payload as RuntimeStore);
|
||||||
if (!isProduction) {
|
if (!isProduction) {
|
||||||
ontimeQueryClient.setQueryData(RUNTIME, data.payload);
|
ontimeQueryClient.setQueryData(RUNTIME, data.payload);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'ontime-playback': {
|
case 'ontime-playback': {
|
||||||
const state = runtime.getState();
|
const state = runtimeStore.getState();
|
||||||
state.playback = payload;
|
state.timer.playback = payload;
|
||||||
runtime.setState(state);
|
runtimeStore.setState(state);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'ontime-timer': {
|
case 'ontime-timer': {
|
||||||
const state = runtime.getState();
|
const state = runtimeStore.getState();
|
||||||
state.timer = payload;
|
state.timer = payload;
|
||||||
runtime.setState(state);
|
runtimeStore.setState(state);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'ontime-loaded': {
|
case 'ontime-runtime': {
|
||||||
const state = runtime.getState();
|
const state = runtimeStore.getState();
|
||||||
state.loaded = payload;
|
state.runtime = payload;
|
||||||
runtime.setState(state);
|
runtimeStore.setState(state);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'ontime-message': {
|
case 'ontime-message': {
|
||||||
const state = runtime.getState();
|
const state = runtimeStore.getState();
|
||||||
state.message = payload;
|
state.message = payload;
|
||||||
runtime.setState(state);
|
runtimeStore.setState(state);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'ontime-onAir': {
|
case 'ontime-onAir': {
|
||||||
const state = runtime.getState();
|
const state = runtimeStore.getState();
|
||||||
state.onAir = payload;
|
state.onAir = payload;
|
||||||
runtime.setState(state);
|
runtimeStore.setState(state);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
import MultiPartProgressBar from '../../../common/components/multi-part-progress-bar/MultiPartProgressBar';
|
import MultiPartProgressBar from '../../../common/components/multi-part-progress-bar/MultiPartProgressBar';
|
||||||
import { useTimer } from '../../../common/hooks/useSocket';
|
import { useProgressData } from '../../../common/hooks/useSocket';
|
||||||
import useViewSettings from '../../../common/hooks-query/useViewSettings';
|
import useViewSettings from '../../../common/hooks-query/useViewSettings';
|
||||||
|
|
||||||
import styles from './CuesheetProgress.module.scss';
|
import styles from './CuesheetProgress.module.scss';
|
||||||
|
|
||||||
export default function CuesheetProgress() {
|
export default function CuesheetProgress() {
|
||||||
const { data } = useViewSettings();
|
const { data } = useViewSettings();
|
||||||
const timer = useTimer();
|
const { addedTime, current, duration, timeWarning, timeDanger } = useProgressData();
|
||||||
const totalTime = (timer.duration ?? 0) + (timer.addedTime ?? 0);
|
const totalTime = (duration ?? 0) + (addedTime ?? 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MultiPartProgressBar
|
<MultiPartProgressBar
|
||||||
now={timer.current}
|
now={current}
|
||||||
complete={totalTime}
|
complete={totalTime}
|
||||||
normalColor={data!.normalColor}
|
normalColor={data!.normalColor}
|
||||||
warning={timer.timeWarning}
|
warning={timeWarning}
|
||||||
warningColor={data!.warningColor}
|
warningColor={data!.warningColor}
|
||||||
danger={timer.timeDanger}
|
danger={timeDanger}
|
||||||
dangerColor={data!.dangerColor}
|
dangerColor={data!.dangerColor}
|
||||||
className={styles.progressOverride}
|
className={styles.progressOverride}
|
||||||
/>
|
/>
|
||||||
|
|||||||
+5
-4
@@ -1,21 +1,22 @@
|
|||||||
import { useTimer } from '../../../common/hooks/useSocket';
|
import { useClock, useTimer } from '../../../common/hooks/useSocket';
|
||||||
import ClockTime from '../../viewers/common/clock-time/ClockTime';
|
import ClockTime from '../../viewers/common/clock-time/ClockTime';
|
||||||
import RunningTime from '../../viewers/common/running-time/RunningTime';
|
import RunningTime from '../../viewers/common/running-time/RunningTime';
|
||||||
|
|
||||||
import style from './CuesheetTableHeader.module.scss';
|
import style from './CuesheetTableHeader.module.scss';
|
||||||
|
|
||||||
export default function CuesheetTableHeaderTimers() {
|
export default function CuesheetTableHeaderTimers() {
|
||||||
const timer = useTimer();
|
const { current } = useTimer();
|
||||||
|
const { clock } = useClock();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={style.timer}>
|
<div className={style.timer}>
|
||||||
<div className={style.timerLabel}>Running Timer</div>
|
<div className={style.timerLabel}>Running Timer</div>
|
||||||
<RunningTime className={style.value} value={timer.current} hideLeadingZero />
|
<RunningTime className={style.value} value={current} hideLeadingZero />
|
||||||
</div>
|
</div>
|
||||||
<div className={style.clock}>
|
<div className={style.clock}>
|
||||||
<div className={style.clockLabel}>Time Now</div>
|
<div className={style.clockLabel}>Time Now</div>
|
||||||
<ClockTime className={style.value} value={timer.clock} />
|
<ClockTime className={style.value} value={clock} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ interface OperatorEventProps {
|
|||||||
|
|
||||||
// extract this to contain re-renders
|
// extract this to contain re-renders
|
||||||
function RollingTime() {
|
function RollingTime() {
|
||||||
const timer = useTimer();
|
const { current } = useTimer();
|
||||||
return <RunningTime value={timer.current} />;
|
return <RunningTime value={current} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function OperatorEvent(props: OperatorEventProps) {
|
function OperatorEvent(props: OperatorEventProps) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ViewSettings } from 'ontime-types';
|
import { ViewSettings } from 'ontime-types';
|
||||||
|
|
||||||
import MultiPartProgressBar from '../../../common/components/multi-part-progress-bar/MultiPartProgressBar';
|
import MultiPartProgressBar from '../../../common/components/multi-part-progress-bar/MultiPartProgressBar';
|
||||||
import { useTimer } from '../../../common/hooks/useSocket';
|
import { useProgressData } from '../../../common/hooks/useSocket';
|
||||||
|
|
||||||
import styles from './StatusBar.module.scss';
|
import styles from './StatusBar.module.scss';
|
||||||
|
|
||||||
@@ -11,18 +11,17 @@ interface StatusBarProgressProps {
|
|||||||
|
|
||||||
export default function StatusBarProgress(props: StatusBarProgressProps) {
|
export default function StatusBarProgress(props: StatusBarProgressProps) {
|
||||||
const { viewSettings } = props;
|
const { viewSettings } = props;
|
||||||
|
const { addedTime, current, duration, timeWarning, timeDanger } = useProgressData();
|
||||||
const timer = useTimer();
|
const totalTime = (duration ?? 0) + (addedTime ?? 0);
|
||||||
const totalTime = (timer.duration ?? 0) + (timer.addedTime ?? 0);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MultiPartProgressBar
|
<MultiPartProgressBar
|
||||||
now={timer.current}
|
now={current}
|
||||||
complete={totalTime}
|
complete={totalTime}
|
||||||
normalColor={viewSettings.normalColor}
|
normalColor={viewSettings.normalColor}
|
||||||
warning={timer?.timeWarning}
|
warning={timeWarning}
|
||||||
warningColor={viewSettings.warningColor}
|
warningColor={viewSettings.warningColor}
|
||||||
danger={timer?.timeDanger}
|
danger={timeDanger}
|
||||||
dangerColor={viewSettings.dangerColor}
|
dangerColor={viewSettings.dangerColor}
|
||||||
className={styles.progressOverride}
|
className={styles.progressOverride}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useMemo } from 'react';
|
|||||||
import { MaybeNumber, Playback } from 'ontime-types';
|
import { MaybeNumber, Playback } from 'ontime-types';
|
||||||
|
|
||||||
import PlaybackIcon from '../../../common/components/playback-icon/PlaybackIcon';
|
import PlaybackIcon from '../../../common/components/playback-icon/PlaybackIcon';
|
||||||
import { useTimer } from '../../../common/hooks/useSocket';
|
import { useClock, useTimer } from '../../../common/hooks/useSocket';
|
||||||
import { cx } from '../../../common/utils/styleUtils';
|
import { cx } from '../../../common/utils/styleUtils';
|
||||||
import ClockTime from '../../viewers/common/clock-time/ClockTime';
|
import ClockTime from '../../viewers/common/clock-time/ClockTime';
|
||||||
import RunningTime from '../../viewers/common/running-time/RunningTime';
|
import RunningTime from '../../viewers/common/running-time/RunningTime';
|
||||||
@@ -23,6 +23,7 @@ export default function StatusBarTimers(props: StatusBarTimersProps) {
|
|||||||
const { projectTitle, playback, selectedEventId, firstStart, firstId, lastEnd, lastId } = props;
|
const { projectTitle, playback, selectedEventId, firstStart, firstId, lastEnd, lastId } = props;
|
||||||
|
|
||||||
const timer = useTimer();
|
const timer = useTimer();
|
||||||
|
const { clock } = useClock();
|
||||||
|
|
||||||
const getTimeStart = (): MaybeNumber => {
|
const getTimeStart = (): MaybeNumber => {
|
||||||
if (firstStart === undefined) {
|
if (firstStart === undefined) {
|
||||||
@@ -61,7 +62,7 @@ export default function StatusBarTimers(props: StatusBarTimersProps) {
|
|||||||
{PlaybackIconComponent}
|
{PlaybackIconComponent}
|
||||||
<div className={styles.timeNow}>
|
<div className={styles.timeNow}>
|
||||||
<span className={styles.label}>Time now</span>
|
<span className={styles.label}>Time now</span>
|
||||||
<ClockTime className={styles.timer} value={timer.clock} />
|
<ClockTime className={styles.timer} value={clock} />
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.elapsedTime}>
|
<div className={styles.elapsedTime}>
|
||||||
<span className={styles.label}>Elapsed time</span>
|
<span className={styles.label}>Elapsed time</span>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ComponentType, useMemo } from 'react';
|
import { ComponentType, useMemo } from 'react';
|
||||||
import { TimeManagerType } from 'common/models/TimeManager.type';
|
import { ViewExtendedTimer } from 'common/models/TimeManager.type';
|
||||||
import { Message, OntimeEvent, ProjectData, Settings, SupportedEvent, TimerMessage, ViewSettings } from 'ontime-types';
|
import { Message, OntimeEvent, ProjectData, Settings, SupportedEvent, TimerMessage, ViewSettings } from 'ontime-types';
|
||||||
import { useStore } from 'zustand';
|
import { useStore } from 'zustand';
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ import useProjectData from '../../common/hooks-query/useProjectData';
|
|||||||
import useRundown from '../../common/hooks-query/useRundown';
|
import useRundown from '../../common/hooks-query/useRundown';
|
||||||
import useSettings from '../../common/hooks-query/useSettings';
|
import useSettings from '../../common/hooks-query/useSettings';
|
||||||
import useViewSettings from '../../common/hooks-query/useViewSettings';
|
import useViewSettings from '../../common/hooks-query/useViewSettings';
|
||||||
import { runtime } from '../../common/stores/runtime';
|
import { runtimeStore } from '../../common/stores/runtime';
|
||||||
import { useViewOptionsStore } from '../../common/stores/viewOptions';
|
import { useViewOptionsStore } from '../../common/stores/viewOptions';
|
||||||
|
|
||||||
type WithDataProps = {
|
type WithDataProps = {
|
||||||
@@ -20,7 +20,7 @@ type WithDataProps = {
|
|||||||
publicEventNow: OntimeEvent | null;
|
publicEventNow: OntimeEvent | null;
|
||||||
eventNext: OntimeEvent | null;
|
eventNext: OntimeEvent | null;
|
||||||
publicEventNext: OntimeEvent | null;
|
publicEventNext: OntimeEvent | null;
|
||||||
time: TimeManagerType;
|
time: ViewExtendedTimer;
|
||||||
events: OntimeEvent[];
|
events: OntimeEvent[];
|
||||||
backstageEvents: OntimeEvent[];
|
backstageEvents: OntimeEvent[];
|
||||||
selectedId: string | null;
|
selectedId: string | null;
|
||||||
@@ -55,11 +55,11 @@ const withData = <P extends WithDataProps>(Component: ComponentType<P>) => {
|
|||||||
}, [rundownData]);
|
}, [rundownData]);
|
||||||
|
|
||||||
// websocket data
|
// websocket data
|
||||||
const { timer, message, playback, onAir, eventNext, publicEventNext, publicEventNow, eventNow, loaded } =
|
const { clock, timer, message, onAir, eventNext, publicEventNext, publicEventNow, eventNow } =
|
||||||
useStore(runtime);
|
useStore(runtimeStore);
|
||||||
const publicSelectedId = loaded.selectedPublicEventId;
|
const publicSelectedId = publicEventNow?.id ?? null;
|
||||||
const selectedId = loaded.selectedEventId;
|
const selectedId = eventNow?.id ?? null;
|
||||||
const nextId = loaded.nextEventId;
|
const nextId = eventNext?.id ?? null;
|
||||||
|
|
||||||
/******************************************/
|
/******************************************/
|
||||||
/*** + TimeManagerType ***/
|
/*** + TimeManagerType ***/
|
||||||
@@ -69,7 +69,10 @@ const withData = <P extends WithDataProps>(Component: ComponentType<P>) => {
|
|||||||
|
|
||||||
const TimeManagerType = {
|
const TimeManagerType = {
|
||||||
...timer,
|
...timer,
|
||||||
playback,
|
clock,
|
||||||
|
timerType: eventNow?.timerType ?? null,
|
||||||
|
timeWarning: eventNow?.timeWarning ?? null,
|
||||||
|
timeDanger: eventNow?.timeWarning ?? null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// prevent render until we get all the data we need
|
// prevent render until we get all the data we need
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import TitleCard from '../../../common/components/title-card/TitleCard';
|
|||||||
import { getBackstageOptions } from '../../../common/components/view-params-editor/constants';
|
import { getBackstageOptions } from '../../../common/components/view-params-editor/constants';
|
||||||
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
||||||
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
||||||
import { TimeManagerType } from '../../../common/models/TimeManager.type';
|
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
|
||||||
import { formatTime, getDefaultFormat } from '../../../common/utils/time';
|
import { formatTime, getDefaultFormat } from '../../../common/utils/time';
|
||||||
import { useTranslation } from '../../../translation/TranslationProvider';
|
import { useTranslation } from '../../../translation/TranslationProvider';
|
||||||
import { titleVariants } from '../common/animation';
|
import { titleVariants } from '../common/animation';
|
||||||
@@ -27,7 +27,7 @@ interface BackstageProps {
|
|||||||
publ: Message;
|
publ: Message;
|
||||||
eventNow: OntimeEvent | null;
|
eventNow: OntimeEvent | null;
|
||||||
eventNext: OntimeEvent | null;
|
eventNext: OntimeEvent | null;
|
||||||
time: TimeManagerType;
|
time: ViewExtendedTimer;
|
||||||
backstageEvents: OntimeEvent[];
|
backstageEvents: OntimeEvent[];
|
||||||
selectedId: string | null;
|
selectedId: string | null;
|
||||||
general: ProjectData;
|
general: ProjectData;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import NavigationMenu from '../../../common/components/navigation-menu/Navigatio
|
|||||||
import { getClockOptions } from '../../../common/components/view-params-editor/constants';
|
import { getClockOptions } from '../../../common/components/view-params-editor/constants';
|
||||||
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
||||||
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
||||||
import { TimeManagerType } from '../../../common/models/TimeManager.type';
|
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
|
||||||
import { OverridableOptions } from '../../../common/models/View.types';
|
import { OverridableOptions } from '../../../common/models/View.types';
|
||||||
import { formatTime, getDefaultFormat } from '../../../common/utils/time';
|
import { formatTime, getDefaultFormat } from '../../../common/utils/time';
|
||||||
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
|
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
|
||||||
@@ -16,7 +16,7 @@ import './Clock.scss';
|
|||||||
|
|
||||||
interface ClockProps {
|
interface ClockProps {
|
||||||
isMirrored: boolean;
|
isMirrored: boolean;
|
||||||
time: TimeManagerType;
|
time: ViewExtendedTimer;
|
||||||
viewSettings: ViewSettings;
|
viewSettings: ViewSettings;
|
||||||
settings: Settings | undefined;
|
settings: Settings | undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { TimerType } from 'ontime-types';
|
import { TimerType } from 'ontime-types';
|
||||||
|
|
||||||
import type { TimeManagerType } from '../../../common/models/TimeManager.type';
|
import type { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
|
||||||
|
|
||||||
type TimerTypeParams = Pick<TimeManagerType, 'timerType' | 'current' | 'elapsed' | 'clock'>;
|
type TimerTypeParams = Pick<ViewExtendedTimer, 'timerType' | 'current' | 'elapsed' | 'clock'>;
|
||||||
|
|
||||||
export function getTimerByType(timerObject?: TimerTypeParams): number | null {
|
export function getTimerByType(timerObject?: TimerTypeParams): number | null {
|
||||||
if (!timerObject) {
|
if (!timerObject) {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import NavigationMenu from '../../../common/components/navigation-menu/Navigatio
|
|||||||
import { getCountdownOptions } from '../../../common/components/view-params-editor/constants';
|
import { getCountdownOptions } from '../../../common/components/view-params-editor/constants';
|
||||||
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
||||||
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
||||||
import { TimeManagerType } from '../../../common/models/TimeManager.type';
|
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
|
||||||
import { formatTime, getDefaultFormat } from '../../../common/utils/time';
|
import { formatTime, getDefaultFormat } from '../../../common/utils/time';
|
||||||
import { useTranslation } from '../../../translation/TranslationProvider';
|
import { useTranslation } from '../../../translation/TranslationProvider';
|
||||||
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
|
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
|
||||||
@@ -21,7 +21,7 @@ import './Countdown.scss';
|
|||||||
interface CountdownProps {
|
interface CountdownProps {
|
||||||
isMirrored: boolean;
|
isMirrored: boolean;
|
||||||
backstageEvents: OntimeEvent[];
|
backstageEvents: OntimeEvent[];
|
||||||
time: TimeManagerType;
|
time: ViewExtendedTimer;
|
||||||
selectedId: string | null;
|
selectedId: string | null;
|
||||||
viewSettings: ViewSettings;
|
viewSettings: ViewSettings;
|
||||||
settings: Settings | undefined;
|
settings: Settings | undefined;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { OntimeEvent, Playback } from 'ontime-types';
|
import { OntimeEvent, Playback } from 'ontime-types';
|
||||||
|
|
||||||
import { TimeManagerType } from '../../../common/models/TimeManager.type';
|
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
|
||||||
|
|
||||||
export enum TimerMessage {
|
export enum TimerMessage {
|
||||||
toStart = 'to_start',
|
toStart = 'to_start',
|
||||||
@@ -19,7 +19,7 @@ export const sanitiseTitle = (title: string | null) => (title ? title : '{no tit
|
|||||||
* Returns a parsed timer and relevant status message
|
* Returns a parsed timer and relevant status message
|
||||||
*/
|
*/
|
||||||
export const fetchTimerData = (
|
export const fetchTimerData = (
|
||||||
time: TimeManagerType,
|
time: ViewExtendedTimer,
|
||||||
follow: OntimeEvent,
|
follow: OntimeEvent,
|
||||||
selectedId: string | null,
|
selectedId: string | null,
|
||||||
): { message: TimerMessage; timer: number } => {
|
): { message: TimerMessage; timer: number } => {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import NavigationMenu from '../../../common/components/navigation-menu/Navigatio
|
|||||||
import { MINIMAL_TIMER_OPTIONS } from '../../../common/components/view-params-editor/constants';
|
import { MINIMAL_TIMER_OPTIONS } from '../../../common/components/view-params-editor/constants';
|
||||||
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
||||||
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
||||||
import { TimeManagerType } from '../../../common/models/TimeManager.type';
|
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
|
||||||
import { OverridableOptions } from '../../../common/models/View.types';
|
import { OverridableOptions } from '../../../common/models/View.types';
|
||||||
import { isStringBoolean } from '../../../common/utils/viewUtils';
|
import { isStringBoolean } from '../../../common/utils/viewUtils';
|
||||||
import { useTranslation } from '../../../translation/TranslationProvider';
|
import { useTranslation } from '../../../translation/TranslationProvider';
|
||||||
@@ -19,7 +19,7 @@ import './MinimalTimer.scss';
|
|||||||
interface MinimalTimerProps {
|
interface MinimalTimerProps {
|
||||||
isMirrored: boolean;
|
isMirrored: boolean;
|
||||||
pres: TimerMessage;
|
pres: TimerMessage;
|
||||||
time: TimeManagerType;
|
time: ViewExtendedTimer;
|
||||||
viewSettings: ViewSettings;
|
viewSettings: ViewSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import TitleCard from '../../../common/components/title-card/TitleCard';
|
|||||||
import { getPublicOptions } from '../../../common/components/view-params-editor/constants';
|
import { getPublicOptions } from '../../../common/components/view-params-editor/constants';
|
||||||
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
||||||
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
||||||
import { TimeManagerType } from '../../../common/models/TimeManager.type';
|
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
|
||||||
import { formatTime, getDefaultFormat } from '../../../common/utils/time';
|
import { formatTime, getDefaultFormat } from '../../../common/utils/time';
|
||||||
import { useTranslation } from '../../../translation/TranslationProvider';
|
import { useTranslation } from '../../../translation/TranslationProvider';
|
||||||
import { titleVariants } from '../common/animation';
|
import { titleVariants } from '../common/animation';
|
||||||
@@ -25,7 +25,7 @@ interface BackstageProps {
|
|||||||
publ: Message;
|
publ: Message;
|
||||||
publicEventNow: OntimeEvent | null;
|
publicEventNow: OntimeEvent | null;
|
||||||
publicEventNext: OntimeEvent | null;
|
publicEventNext: OntimeEvent | null;
|
||||||
time: TimeManagerType;
|
time: ViewExtendedTimer;
|
||||||
events: OntimeEvent[];
|
events: OntimeEvent[];
|
||||||
publicSelectedId: string | null;
|
publicSelectedId: string | null;
|
||||||
general: ProjectData;
|
general: ProjectData;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { getStudioClockOptions } from '../../../common/components/view-params-ed
|
|||||||
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
||||||
import useFitText from '../../../common/hooks/useFitText';
|
import useFitText from '../../../common/hooks/useFitText';
|
||||||
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
||||||
import { TimeManagerType } from '../../../common/models/TimeManager.type';
|
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
|
||||||
import { formatTime, getDefaultFormat } from '../../../common/utils/time';
|
import { formatTime, getDefaultFormat } from '../../../common/utils/time';
|
||||||
import { isStringBoolean } from '../../../common/utils/viewUtils';
|
import { isStringBoolean } from '../../../common/utils/viewUtils';
|
||||||
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
|
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
|
||||||
@@ -22,7 +22,7 @@ import './StudioClock.scss';
|
|||||||
interface StudioClockProps {
|
interface StudioClockProps {
|
||||||
isMirrored: boolean;
|
isMirrored: boolean;
|
||||||
eventNext: OntimeEvent | null;
|
eventNext: OntimeEvent | null;
|
||||||
time: TimeManagerType;
|
time: ViewExtendedTimer;
|
||||||
backstageEvents: OntimeRundown;
|
backstageEvents: OntimeRundown;
|
||||||
selectedId: string | null;
|
selectedId: string | null;
|
||||||
nextId: string | null;
|
nextId: string | null;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import TitleCard from '../../../common/components/title-card/TitleCard';
|
|||||||
import { getTimerOptions } from '../../../common/components/view-params-editor/constants';
|
import { getTimerOptions } from '../../../common/components/view-params-editor/constants';
|
||||||
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
||||||
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
||||||
import { TimeManagerType } from '../../../common/models/TimeManager.type';
|
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
|
||||||
import { formatTime, getDefaultFormat } from '../../../common/utils/time';
|
import { formatTime, getDefaultFormat } from '../../../common/utils/time';
|
||||||
import { isStringBoolean } from '../../../common/utils/viewUtils';
|
import { isStringBoolean } from '../../../common/utils/viewUtils';
|
||||||
import { useTranslation } from '../../../translation/TranslationProvider';
|
import { useTranslation } from '../../../translation/TranslationProvider';
|
||||||
@@ -42,7 +42,7 @@ interface TimerProps {
|
|||||||
external: Message;
|
external: Message;
|
||||||
eventNow: OntimeEvent | null;
|
eventNow: OntimeEvent | null;
|
||||||
eventNext: OntimeEvent | null;
|
eventNext: OntimeEvent | null;
|
||||||
time: TimeManagerType;
|
time: ViewExtendedTimer;
|
||||||
viewSettings: ViewSettings;
|
viewSettings: ViewSettings;
|
||||||
settings: Settings | undefined;
|
settings: Settings | undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-19
@@ -157,28 +157,13 @@ export const startServer = async () => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Module initialises the services and provides initial payload for the store
|
* Module initialises the services and provides initial payload for the store
|
||||||
* Currently registered objects in store
|
|
||||||
*
|
|
||||||
* - Message Service timerMessage
|
|
||||||
* - Message Service publicMessage
|
|
||||||
* - Message Service lowerMessage
|
|
||||||
* - Message Service externalMessage
|
|
||||||
*
|
|
||||||
* - Runtime Service onAir (derived from playback)
|
|
||||||
* - Runtime Service timer
|
|
||||||
* - Runtime Service playback
|
|
||||||
* - Runtime Service loaded // TODO: rename to runtime ??
|
|
||||||
* - Runtime Service eventNow
|
|
||||||
* - Runtime Service publicEventNow
|
|
||||||
* - Runtime Service eventNext
|
|
||||||
* - Runtime Service publicEventNext
|
|
||||||
*/
|
*/
|
||||||
eventStore.init({
|
eventStore.init({
|
||||||
message: messageService,
|
clock: state.clock,
|
||||||
onAir: state.playback !== Playback.Stop,
|
|
||||||
timer: state.timer,
|
timer: state.timer,
|
||||||
playback: state.playback,
|
onAir: state.timer.playback !== Playback.Stop,
|
||||||
loaded: state.runtime,
|
message: messageService.getState(),
|
||||||
|
runtime: state.runtime,
|
||||||
eventNow: state.eventNow,
|
eventNow: state.eventNow,
|
||||||
publicEventNow: state.publicEventNow,
|
publicEventNow: state.publicEventNow,
|
||||||
eventNext: state.eventNext,
|
eventNext: state.eventNext,
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export class EventLoader {
|
|||||||
* finds the previous event
|
* finds the previous event
|
||||||
* @return {object | undefined}
|
* @return {object | undefined}
|
||||||
*/
|
*/
|
||||||
static findPrevious(currentEventId: string | null): OntimeEvent | null {
|
static findPrevious(currentEventId?: string): OntimeEvent | null {
|
||||||
const timedEvents = EventLoader.getPlayableEvents();
|
const timedEvents = EventLoader.getPlayableEvents();
|
||||||
if (!timedEvents || !timedEvents.length) {
|
if (!timedEvents || !timedEvents.length) {
|
||||||
return null;
|
return null;
|
||||||
@@ -87,7 +87,7 @@ export class EventLoader {
|
|||||||
* finds the next event
|
* finds the next event
|
||||||
* @return {object | undefined}
|
* @return {object | undefined}
|
||||||
*/
|
*/
|
||||||
static findNext(currentEventId: string | null): OntimeEvent | null {
|
static findNext(currentEventId?: string): OntimeEvent | null {
|
||||||
const timedEvents = EventLoader.getPlayableEvents();
|
const timedEvents = EventLoader.getPlayableEvents();
|
||||||
if (!timedEvents || !timedEvents.length) {
|
if (!timedEvents || !timedEvents.length) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ export class TimerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
if (!state.runtime.selectedEventId) {
|
if (!state.eventNow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.playback === Playback.Play) {
|
if (state.timer.playback === Playback.Play) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,14 +36,14 @@ export class TimerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pause() {
|
pause() {
|
||||||
if (state.playback !== Playback.Play) {
|
if (state.timer.playback !== Playback.Play) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
stateMutations.timer.pause();
|
stateMutations.timer.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
if (state.playback === Playback.Stop) {
|
if (state.timer.playback === Playback.Stop) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
stateMutations.timer.stop();
|
stateMutations.timer.stop();
|
||||||
@@ -54,7 +54,7 @@ export class TimerService {
|
|||||||
* @param {number} amount
|
* @param {number} amount
|
||||||
*/
|
*/
|
||||||
addTime(amount: number) {
|
addTime(amount: number) {
|
||||||
if (state.runtime.selectedEventId === null) {
|
if (state.eventNow === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
stateMutations.timer.addTime(amount);
|
stateMutations.timer.addTime(amount);
|
||||||
|
|||||||
@@ -16,14 +16,16 @@ describe('getExpectedFinish()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 10,
|
timeEnd: 10,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
duration: 10,
|
duration: 10,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
pausedAt: null,
|
|
||||||
startedAt: null,
|
startedAt: null,
|
||||||
timerType: TimerType.CountDown,
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
const calculatedFinish = getExpectedFinish(state);
|
const calculatedFinish = getExpectedFinish(state);
|
||||||
@@ -33,14 +35,16 @@ describe('getExpectedFinish()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 20,
|
timeEnd: 20,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
duration: 10,
|
duration: 10,
|
||||||
finishedAt: 20, // <---- finished at
|
finishedAt: 20, // <---- finished at
|
||||||
pausedAt: null,
|
|
||||||
startedAt: 10,
|
startedAt: 10,
|
||||||
timerType: TimerType.CountDown,
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
const calculatedFinish = getExpectedFinish(state);
|
const calculatedFinish = getExpectedFinish(state);
|
||||||
@@ -50,14 +54,16 @@ describe('getExpectedFinish()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 11,
|
timeEnd: 11,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
duration: 10,
|
duration: 10,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
pausedAt: null,
|
|
||||||
startedAt: 1,
|
startedAt: 1,
|
||||||
timerType: TimerType.CountDown,
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
const calculatedFinish = getExpectedFinish(state);
|
const calculatedFinish = getExpectedFinish(state);
|
||||||
@@ -67,14 +73,16 @@ describe('getExpectedFinish()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 11,
|
timeEnd: 11,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 20,
|
addedTime: 20,
|
||||||
duration: 10,
|
duration: 10,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
pausedAt: null,
|
|
||||||
startedAt: 1,
|
startedAt: 1,
|
||||||
timerType: TimerType.CountDown,
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -85,14 +93,16 @@ describe('getExpectedFinish()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 11,
|
timeEnd: 11,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: -10,
|
addedTime: -10,
|
||||||
duration: 10,
|
duration: 10,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
pausedAt: null,
|
|
||||||
startedAt: 1,
|
startedAt: 1,
|
||||||
timerType: TimerType.CountDown,
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -103,14 +113,16 @@ describe('getExpectedFinish()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 11,
|
timeEnd: 11,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: -100,
|
addedTime: -100,
|
||||||
duration: 10,
|
duration: 10,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
pausedAt: null,
|
|
||||||
startedAt: 1,
|
startedAt: 1,
|
||||||
timerType: TimerType.CountDown,
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -121,14 +133,16 @@ describe('getExpectedFinish()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 0,
|
timeEnd: 0,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
duration: 0,
|
duration: 0,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
pausedAt: null,
|
|
||||||
startedAt: 1,
|
startedAt: 1,
|
||||||
timerType: TimerType.CountDown,
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -139,14 +153,16 @@ describe('getExpectedFinish()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 10,
|
timeEnd: 10,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
duration: dayInMs,
|
duration: dayInMs,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
pausedAt: null,
|
|
||||||
startedAt: 10,
|
startedAt: 10,
|
||||||
timerType: TimerType.CountDown,
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -158,14 +174,16 @@ describe('getExpectedFinish()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 30,
|
timeEnd: 30,
|
||||||
|
timerType: TimerType.TimeToEnd,
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 10,
|
addedTime: 10,
|
||||||
duration: dayInMs,
|
duration: dayInMs,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
pausedAt: null,
|
|
||||||
startedAt: 10,
|
startedAt: 10,
|
||||||
timerType: TimerType.TimeToEnd,
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -176,13 +194,15 @@ describe('getExpectedFinish()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 600000, // 00:10:00
|
timeEnd: 600000, // 00:10:00
|
||||||
|
timerType: TimerType.TimeToEnd,
|
||||||
},
|
},
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
pausedAt: null,
|
|
||||||
startedAt: 79200000, // 22:00:00
|
startedAt: 79200000, // 22:00:00
|
||||||
timerType: TimerType.TimeToEnd,
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -198,15 +218,17 @@ describe('getCurrent()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 30,
|
timeEnd: 30,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
|
clock: 0,
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 10,
|
addedTime: 10,
|
||||||
clock: 0,
|
|
||||||
duration: 111, // <-- we take the duration value
|
duration: 111, // <-- we take the duration value
|
||||||
startedAt: null,
|
startedAt: null,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
timerType: TimerType.CountDown,
|
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -217,14 +239,17 @@ describe('getCurrent()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 10,
|
timeEnd: 10,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
|
clock: 1,
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
clock: 1,
|
|
||||||
duration: 10,
|
duration: 10,
|
||||||
startedAt: 0,
|
startedAt: 0,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
timerType: TimerType.CountDown,
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -235,15 +260,17 @@ describe('getCurrent()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 10,
|
timeEnd: 10,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
|
clock: 1,
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 10,
|
addedTime: 10,
|
||||||
clock: 1,
|
|
||||||
duration: 10,
|
duration: 10,
|
||||||
startedAt: 0,
|
startedAt: 0,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
timerType: TimerType.CountDown,
|
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -254,15 +281,17 @@ describe('getCurrent()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 20,
|
timeEnd: 20,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
|
clock: 10,
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
clock: 10,
|
|
||||||
duration: dayInMs + 10,
|
duration: dayInMs + 10,
|
||||||
startedAt: 10,
|
startedAt: 10,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
timerType: TimerType.CountDown,
|
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -273,15 +302,17 @@ describe('getCurrent()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 20,
|
timeEnd: 20,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
|
clock: 5,
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
clock: 5,
|
|
||||||
duration: dayInMs + 10,
|
duration: dayInMs + 10,
|
||||||
startedAt: 10,
|
startedAt: 10,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
timerType: TimerType.CountDown,
|
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -292,15 +323,17 @@ describe('getCurrent()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 20,
|
timeEnd: 20,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
|
clock: 5,
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 20,
|
addedTime: 20,
|
||||||
clock: 5,
|
|
||||||
duration: dayInMs + 10,
|
duration: dayInMs + 10,
|
||||||
startedAt: 10,
|
startedAt: 10,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
timerType: TimerType.CountDown,
|
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -312,15 +345,17 @@ describe('getCurrent()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 100,
|
timeEnd: 100,
|
||||||
|
timerType: TimerType.TimeToEnd,
|
||||||
},
|
},
|
||||||
|
clock: 30,
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
clock: 30,
|
|
||||||
duration: 100,
|
duration: 100,
|
||||||
startedAt: 10,
|
startedAt: 10,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
timerType: TimerType.TimeToEnd,
|
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -331,15 +366,17 @@ describe('getCurrent()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 100,
|
timeEnd: 100,
|
||||||
|
timerType: TimerType.TimeToEnd,
|
||||||
},
|
},
|
||||||
|
clock: 30,
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 7,
|
addedTime: 7,
|
||||||
clock: 30,
|
|
||||||
duration: 100,
|
duration: 100,
|
||||||
startedAt: 10,
|
startedAt: 10,
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
timerType: TimerType.TimeToEnd,
|
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -350,15 +387,17 @@ describe('getCurrent()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 600000, // 00:10:00
|
timeEnd: 600000, // 00:10:00
|
||||||
|
timerType: TimerType.TimeToEnd,
|
||||||
},
|
},
|
||||||
|
clock: 79500000, // 22:05:00
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
clock: 79500000, // 22:05:00
|
|
||||||
duration: Infinity, // not relevant,
|
duration: Infinity, // not relevant,
|
||||||
startedAt: 79200000, // 22:00:00
|
startedAt: 79200000, // 22:00:00
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
timerType: TimerType.TimeToEnd,
|
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -369,15 +408,17 @@ describe('getCurrent()', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 600000, // 00:10:00
|
timeEnd: 600000, // 00:10:00
|
||||||
|
timerType: TimerType.TimeToEnd,
|
||||||
},
|
},
|
||||||
|
clock: 79500000, // 22:05:00
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
clock: 79500000, // 22:05:00
|
|
||||||
duration: Infinity, // not relevant,
|
duration: Infinity, // not relevant,
|
||||||
startedAt: 79200000, // 22:00:00
|
startedAt: 79200000, // 22:00:00
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
timerType: TimerType.TimeToEnd,
|
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -393,15 +434,17 @@ describe('getExpectedFinish() and getCurrentTime() combined', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 10,
|
timeEnd: 10,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
|
clock: 0,
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 0,
|
addedTime: 0,
|
||||||
clock: 0,
|
|
||||||
duration,
|
duration,
|
||||||
startedAt: 0,
|
startedAt: 0,
|
||||||
pausedAt: null,
|
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
timerType: TimerType.CountDown,
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -419,15 +462,17 @@ describe('getExpectedFinish() and getCurrentTime() combined', () => {
|
|||||||
const state = {
|
const state = {
|
||||||
eventNow: {
|
eventNow: {
|
||||||
timeEnd: 10,
|
timeEnd: 10,
|
||||||
|
timerType: TimerType.CountDown,
|
||||||
},
|
},
|
||||||
|
clock: 5,
|
||||||
timer: {
|
timer: {
|
||||||
addedTime: 3,
|
addedTime: 3,
|
||||||
clock: 5,
|
|
||||||
duration,
|
duration,
|
||||||
startedAt: 0,
|
startedAt: 0,
|
||||||
pausedAt: null,
|
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
timerType: TimerType.CountDown,
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|
||||||
@@ -449,8 +494,8 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
const expectedFinish = startedAt + duration;
|
const expectedFinish = startedAt + duration;
|
||||||
const previousTime = expectedFinish - testSkipLimit / 2;
|
const previousTime = expectedFinish - testSkipLimit / 2;
|
||||||
const state = {
|
const state = {
|
||||||
|
clock: previousTime,
|
||||||
timer: {
|
timer: {
|
||||||
clock: previousTime,
|
|
||||||
expectedFinish,
|
expectedFinish,
|
||||||
startedAt,
|
startedAt,
|
||||||
},
|
},
|
||||||
@@ -459,7 +504,7 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||||
|
|
||||||
// @ts-expect-error -- cheating in tests
|
// @ts-expect-error -- cheating in tests
|
||||||
state.timer.clock += testSkipLimit;
|
state.clock += testSkipLimit;
|
||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -470,8 +515,8 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
const previousTime = startedAt + testSkipLimit / 2;
|
const previousTime = startedAt + testSkipLimit / 2;
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
|
clock: previousTime,
|
||||||
timer: {
|
timer: {
|
||||||
clock: previousTime,
|
|
||||||
expectedFinish,
|
expectedFinish,
|
||||||
startedAt,
|
startedAt,
|
||||||
},
|
},
|
||||||
@@ -480,7 +525,7 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||||
|
|
||||||
// @ts-expect-error -- cheating in tests
|
// @ts-expect-error -- cheating in tests
|
||||||
state.timer.clock += testSkipLimit;
|
state.clock += testSkipLimit;
|
||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -490,8 +535,8 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
const previousTime = dayInMs - 1;
|
const previousTime = dayInMs - 1;
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
|
clock: previousTime,
|
||||||
timer: {
|
timer: {
|
||||||
clock: previousTime,
|
|
||||||
expectedFinish,
|
expectedFinish,
|
||||||
startedAt,
|
startedAt,
|
||||||
},
|
},
|
||||||
@@ -500,7 +545,7 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||||
|
|
||||||
// @ts-expect-error -- cheating in tests
|
// @ts-expect-error -- cheating in tests
|
||||||
state.timer.clock = testSkipLimit - 2;
|
state.clock = testSkipLimit - 2;
|
||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -510,8 +555,8 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
const previousTime = startedAt + 1;
|
const previousTime = startedAt + 1;
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
|
clock: previousTime,
|
||||||
timer: {
|
timer: {
|
||||||
clock: previousTime,
|
|
||||||
expectedFinish,
|
expectedFinish,
|
||||||
startedAt,
|
startedAt,
|
||||||
},
|
},
|
||||||
@@ -520,7 +565,7 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||||
|
|
||||||
// @ts-expect-error -- cheating in tests
|
// @ts-expect-error -- cheating in tests
|
||||||
state.timer.clock -= testSkipLimit;
|
state.clock -= testSkipLimit;
|
||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -531,8 +576,8 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
const previousTime = expectedFinish - testSkipLimit / 2;
|
const previousTime = expectedFinish - testSkipLimit / 2;
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
|
clock: previousTime,
|
||||||
timer: {
|
timer: {
|
||||||
clock: previousTime,
|
|
||||||
expectedFinish,
|
expectedFinish,
|
||||||
startedAt,
|
startedAt,
|
||||||
},
|
},
|
||||||
@@ -541,7 +586,7 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||||
|
|
||||||
// @ts-expect-error -- cheating in tests
|
// @ts-expect-error -- cheating in tests
|
||||||
state.timer.clock += testSkipLimit + 1;
|
state.clock += testSkipLimit + 1;
|
||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(true);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -552,8 +597,8 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
const previousTime = startedAt + testSkipLimit / 2;
|
const previousTime = startedAt + testSkipLimit / 2;
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
|
clock: previousTime,
|
||||||
timer: {
|
timer: {
|
||||||
clock: previousTime,
|
|
||||||
expectedFinish,
|
expectedFinish,
|
||||||
startedAt,
|
startedAt,
|
||||||
},
|
},
|
||||||
@@ -562,7 +607,7 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||||
|
|
||||||
// @ts-expect-error -- cheating in tests
|
// @ts-expect-error -- cheating in tests
|
||||||
state.timer.clock -= testSkipLimit + 1;
|
state.clock -= testSkipLimit + 1;
|
||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(true);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -572,8 +617,8 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
const previousTime = dayInMs - 3;
|
const previousTime = dayInMs - 3;
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
|
clock: previousTime,
|
||||||
timer: {
|
timer: {
|
||||||
clock: previousTime,
|
|
||||||
expectedFinish,
|
expectedFinish,
|
||||||
startedAt,
|
startedAt,
|
||||||
},
|
},
|
||||||
@@ -582,7 +627,7 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||||
|
|
||||||
// @ts-expect-error -- cheating in tests
|
// @ts-expect-error -- cheating in tests
|
||||||
state.timer.clock = testSkipLimit - 2;
|
state.clock = testSkipLimit - 2;
|
||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(true);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -592,8 +637,8 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
const previousTime = startedAt + 1;
|
const previousTime = startedAt + 1;
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
|
clock: previousTime,
|
||||||
timer: {
|
timer: {
|
||||||
clock: previousTime,
|
|
||||||
expectedFinish,
|
expectedFinish,
|
||||||
startedAt,
|
startedAt,
|
||||||
},
|
},
|
||||||
@@ -602,7 +647,7 @@ describe('skippedOutOfEvent()', () => {
|
|||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(false);
|
||||||
|
|
||||||
// @ts-expect-error -- cheating in tests
|
// @ts-expect-error -- cheating in tests
|
||||||
state.timer.clock -= testSkipLimit + 1;
|
state.clock -= testSkipLimit + 1;
|
||||||
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(true);
|
expect(skippedOutOfEvent(state, previousTime, testSkipLimit)).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1124,14 +1169,17 @@ test('normaliseEndTime()', () => {
|
|||||||
describe('updateRoll()', () => {
|
describe('updateRoll()', () => {
|
||||||
it('it updates running events correctly', () => {
|
it('it updates running events correctly', () => {
|
||||||
const timers = {
|
const timers = {
|
||||||
runtime: {
|
eventNow: {
|
||||||
selectedEventId: '1',
|
id: '1',
|
||||||
},
|
},
|
||||||
|
clock: 11,
|
||||||
timer: {
|
timer: {
|
||||||
current: 10,
|
current: 10,
|
||||||
expectedFinish: 15,
|
expectedFinish: 15,
|
||||||
clock: 11,
|
|
||||||
secondaryTimer: null,
|
secondaryTimer: null,
|
||||||
|
startedAt: 1,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
secondaryTarget: null,
|
secondaryTarget: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
@@ -1149,7 +1197,7 @@ describe('updateRoll()', () => {
|
|||||||
// @ts-expect-error -- cheating for tests
|
// @ts-expect-error -- cheating for tests
|
||||||
timers.timer.expectedFinish = 1000;
|
timers.timer.expectedFinish = 1000;
|
||||||
// @ts-expect-error -- cheating for tests
|
// @ts-expect-error -- cheating for tests
|
||||||
timers.timer.clock = 600;
|
timers.clock = 600;
|
||||||
expected.updatedTimer = 1000 - 600;
|
expected.updatedTimer = 1000 - 600;
|
||||||
|
|
||||||
expect(updateRoll(timers)).toStrictEqual(expected);
|
expect(updateRoll(timers)).toStrictEqual(expected);
|
||||||
@@ -1157,14 +1205,14 @@ describe('updateRoll()', () => {
|
|||||||
|
|
||||||
it('it updates secondary timer', () => {
|
it('it updates secondary timer', () => {
|
||||||
const timers = {
|
const timers = {
|
||||||
runtime: {
|
eventNow: null,
|
||||||
selectedEventId: null,
|
clock: 11,
|
||||||
},
|
|
||||||
timer: {
|
timer: {
|
||||||
current: null,
|
current: null,
|
||||||
expectedFinish: null,
|
expectedFinish: null,
|
||||||
clock: 11,
|
|
||||||
secondaryTimer: 1,
|
secondaryTimer: 1,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
secondaryTarget: 15,
|
secondaryTarget: 15,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
@@ -1181,15 +1229,17 @@ describe('updateRoll()', () => {
|
|||||||
|
|
||||||
it('flags an event end', () => {
|
it('flags an event end', () => {
|
||||||
const timers = {
|
const timers = {
|
||||||
runtime: {
|
eventNow: {
|
||||||
selectedEventId: '1',
|
id: '1',
|
||||||
},
|
},
|
||||||
|
clock: 12,
|
||||||
timer: {
|
timer: {
|
||||||
startedAt: 0,
|
startedAt: 0,
|
||||||
current: 10,
|
current: 10,
|
||||||
expectedFinish: 11,
|
expectedFinish: 11,
|
||||||
clock: 12,
|
|
||||||
secondaryTimer: null,
|
secondaryTimer: null,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
secondaryTarget: null,
|
secondaryTarget: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
@@ -1206,15 +1256,15 @@ describe('updateRoll()', () => {
|
|||||||
|
|
||||||
it('secondary events do not trigger event ends', () => {
|
it('secondary events do not trigger event ends', () => {
|
||||||
const timers = {
|
const timers = {
|
||||||
runtime: {
|
eventNow: null,
|
||||||
selectedEventId: null,
|
clock: 16,
|
||||||
},
|
|
||||||
timer: {
|
timer: {
|
||||||
startedAt: null,
|
startedAt: null,
|
||||||
current: null,
|
current: null,
|
||||||
expectedFinish: null,
|
expectedFinish: null,
|
||||||
clock: 16,
|
|
||||||
secondaryTimer: 1,
|
secondaryTimer: 1,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
secondaryTarget: 15,
|
secondaryTarget: 15,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
@@ -1231,14 +1281,14 @@ describe('updateRoll()', () => {
|
|||||||
|
|
||||||
it('when a secondary timer is finished, it prompts for new event load', () => {
|
it('when a secondary timer is finished, it prompts for new event load', () => {
|
||||||
const timers = {
|
const timers = {
|
||||||
runtime: {
|
eventNow: null,
|
||||||
selectedEventId: null,
|
clock: 15,
|
||||||
},
|
|
||||||
timer: {
|
timer: {
|
||||||
current: null,
|
current: null,
|
||||||
expectedFinish: null,
|
expectedFinish: null,
|
||||||
clock: 15,
|
|
||||||
secondaryTimer: 0,
|
secondaryTimer: 0,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
secondaryTarget: 15,
|
secondaryTarget: 15,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
@@ -1255,15 +1305,17 @@ describe('updateRoll()', () => {
|
|||||||
|
|
||||||
it('counts over midnight', () => {
|
it('counts over midnight', () => {
|
||||||
const timers = {
|
const timers = {
|
||||||
runtime: {
|
eventNow: {
|
||||||
selectedEventId: '1',
|
id: '1',
|
||||||
},
|
},
|
||||||
|
clock: dayInMs - 10,
|
||||||
timer: {
|
timer: {
|
||||||
current: 25,
|
current: 25,
|
||||||
expectedFinish: 10,
|
expectedFinish: 10,
|
||||||
startedAt: 1000,
|
startedAt: 1000,
|
||||||
clock: dayInMs - 10,
|
|
||||||
secondaryTimer: null,
|
secondaryTimer: null,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
secondaryTarget: null,
|
secondaryTarget: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
@@ -1280,15 +1332,17 @@ describe('updateRoll()', () => {
|
|||||||
|
|
||||||
it('rolls over midnight', () => {
|
it('rolls over midnight', () => {
|
||||||
const timers = {
|
const timers = {
|
||||||
runtime: {
|
eventNow: {
|
||||||
selectedEventId: '1',
|
id: '1',
|
||||||
},
|
},
|
||||||
|
clock: 10,
|
||||||
timer: {
|
timer: {
|
||||||
current: dayInMs,
|
current: dayInMs,
|
||||||
expectedFinish: 10,
|
expectedFinish: 10,
|
||||||
startedAt: 1000,
|
startedAt: 1000,
|
||||||
clock: 10,
|
|
||||||
secondaryTimer: null,
|
secondaryTimer: null,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
secondaryTarget: null,
|
secondaryTarget: null,
|
||||||
},
|
},
|
||||||
} as TState;
|
} as TState;
|
||||||
|
|||||||
@@ -36,10 +36,10 @@ class RuntimeService {
|
|||||||
* Checks if a list of IDs is in the current selection
|
* Checks if a list of IDs is in the current selection
|
||||||
*/
|
*/
|
||||||
private affectsLoaded(affectedIds: string[]): boolean {
|
private affectsLoaded(affectedIds: string[]): boolean {
|
||||||
const now = state.runtime.selectedEventId;
|
const now = state.eventNow?.id;
|
||||||
const nowPublic = state.runtime.selectedPublicEventId;
|
const nowPublic = state.publicEventNow?.id;
|
||||||
const next = state.runtime.nextEventId;
|
const next = state.eventNext?.id;
|
||||||
const nextPublic = state.runtime.nextPublicEventId;
|
const nextPublic = state.publicEventNext?.id;
|
||||||
return (
|
return (
|
||||||
affectedIds.includes(now) ||
|
affectedIds.includes(now) ||
|
||||||
affectedIds.includes(nowPublic) ||
|
affectedIds.includes(nowPublic) ||
|
||||||
@@ -50,8 +50,8 @@ class RuntimeService {
|
|||||||
|
|
||||||
private isNewNext() {
|
private isNewNext() {
|
||||||
const timedEvents = EventLoader.getPlayableEvents();
|
const timedEvents = EventLoader.getPlayableEvents();
|
||||||
const now = state.runtime.selectedEventId;
|
const now = state.eventNow?.id;
|
||||||
const next = state.runtime.nextEventId;
|
const next = state.eventNext?.id;
|
||||||
|
|
||||||
// check whether the index of now and next are consecutive
|
// check whether the index of now and next are consecutive
|
||||||
const indexNow = timedEvents.findIndex((event) => event.id === now);
|
const indexNow = timedEvents.findIndex((event) => event.id === now);
|
||||||
@@ -61,8 +61,8 @@ class RuntimeService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// iterate through timed events and see if there are public events between nowPublic and nextPublic
|
// iterate through timed events and see if there are public events between nowPublic and nextPublic
|
||||||
const nowPublic = state.runtime.selectedPublicEventId;
|
const nowPublic = state.publicEventNow?.id;
|
||||||
const nextPublic = state.runtime.nextPublicEventId;
|
const nextPublic = state.publicEventNext?.id;
|
||||||
|
|
||||||
let foundNew = false;
|
let foundNew = false;
|
||||||
let isAfter = false;
|
let isAfter = false;
|
||||||
@@ -93,7 +93,7 @@ class RuntimeService {
|
|||||||
* check whether underlying data of runtime has changed
|
* check whether underlying data of runtime has changed
|
||||||
*/
|
*/
|
||||||
update(affectedIds?: string[]) {
|
update(affectedIds?: string[]) {
|
||||||
const hasLoadedElements = state.runtime.selectedEventId && state.runtime.nextEventId;
|
const hasLoadedElements = state.eventNow && state.eventNext;
|
||||||
if (!hasLoadedElements) {
|
if (!hasLoadedElements) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -107,11 +107,11 @@ class RuntimeService {
|
|||||||
let isNext = false;
|
let isNext = false;
|
||||||
|
|
||||||
if (safeOption || eventInMemory) {
|
if (safeOption || eventInMemory) {
|
||||||
if (state.playback === Playback.Roll) {
|
if (state.timer.playback === Playback.Roll) {
|
||||||
this.roll();
|
this.roll();
|
||||||
}
|
}
|
||||||
// load stuff again, but keep running if our events still exist
|
// load stuff again, but keep running if our events still exist
|
||||||
const eventNow = EventLoader.getEventWithId(state.runtime.selectedEventId);
|
const eventNow = EventLoader.getEventWithId(state.eventNow.id);
|
||||||
if (eventNow) {
|
if (eventNow) {
|
||||||
stateMutations.reload(eventNow);
|
stateMutations.reload(eventNow);
|
||||||
}
|
}
|
||||||
@@ -139,7 +139,7 @@ class RuntimeService {
|
|||||||
|
|
||||||
const timedEvents = EventLoader.getPlayableEvents();
|
const timedEvents = EventLoader.getPlayableEvents();
|
||||||
stateMutations.load(event, timedEvents);
|
stateMutations.load(event, timedEvents);
|
||||||
const success = event.id === state.runtime.selectedEventId;
|
const success = event.id === state.eventNow?.id;
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
logger.info(LogOrigin.Playback, `Loaded event with ID ${event.id}`);
|
logger.info(LogOrigin.Playback, `Loaded event with ID ${event.id}`);
|
||||||
@@ -227,7 +227,7 @@ class RuntimeService {
|
|||||||
* @return {boolean} success - whether an event was loaded
|
* @return {boolean} success - whether an event was loaded
|
||||||
*/
|
*/
|
||||||
loadPrevious(): boolean {
|
loadPrevious(): boolean {
|
||||||
const previousEvent = EventLoader.findPrevious(state.runtime.selectedEventId);
|
const previousEvent = EventLoader.findPrevious(state.eventNow?.id);
|
||||||
if (previousEvent) {
|
if (previousEvent) {
|
||||||
const success = this.loadEvent(previousEvent);
|
const success = this.loadEvent(previousEvent);
|
||||||
return success;
|
return success;
|
||||||
@@ -240,7 +240,7 @@ class RuntimeService {
|
|||||||
* @return {boolean} success
|
* @return {boolean} success
|
||||||
*/
|
*/
|
||||||
loadNext(): boolean {
|
loadNext(): boolean {
|
||||||
const nextEvent = EventLoader.findNext(state.runtime.selectedEventId);
|
const nextEvent = EventLoader.findNext(state.eventNow?.id);
|
||||||
if (nextEvent) {
|
if (nextEvent) {
|
||||||
const success = this.loadEvent(nextEvent);
|
const success = this.loadEvent(nextEvent);
|
||||||
return success;
|
return success;
|
||||||
@@ -254,10 +254,10 @@ class RuntimeService {
|
|||||||
* Starts playback on selected event
|
* Starts playback on selected event
|
||||||
*/
|
*/
|
||||||
start() {
|
start() {
|
||||||
const canStart = validatePlayback(state.playback).start;
|
const canStart = validatePlayback(state.timer.playback).start;
|
||||||
if (canStart) {
|
if (canStart) {
|
||||||
this.eventTimer.start();
|
this.eventTimer.start();
|
||||||
logger.info(LogOrigin.Playback, `Play Mode ${state.playback.toUpperCase()}`);
|
logger.info(LogOrigin.Playback, `Play Mode ${state.timer.playback.toUpperCase()}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,9 +275,9 @@ class RuntimeService {
|
|||||||
* Pauses playback on selected event
|
* Pauses playback on selected event
|
||||||
*/
|
*/
|
||||||
pause() {
|
pause() {
|
||||||
if (validatePlayback(state.playback).pause) {
|
if (validatePlayback(state.timer.playback).pause) {
|
||||||
this.eventTimer.pause();
|
this.eventTimer.pause();
|
||||||
const newState = state.playback;
|
const newState = state.timer.playback;
|
||||||
logger.info(LogOrigin.Playback, `Play Mode ${newState.toUpperCase()}`);
|
logger.info(LogOrigin.Playback, `Play Mode ${newState.toUpperCase()}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,9 +286,9 @@ class RuntimeService {
|
|||||||
* Stops timer and unloads any events
|
* Stops timer and unloads any events
|
||||||
*/
|
*/
|
||||||
stop() {
|
stop() {
|
||||||
if (validatePlayback(state.playback).stop) {
|
if (validatePlayback(state.timer.playback).stop) {
|
||||||
this.eventTimer.stop();
|
this.eventTimer.stop();
|
||||||
const newState = state.playback;
|
const newState = state.timer.playback;
|
||||||
logger.info(LogOrigin.Playback, `Play Mode ${newState.toUpperCase()}`);
|
logger.info(LogOrigin.Playback, `Play Mode ${newState.toUpperCase()}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,7 +297,7 @@ class RuntimeService {
|
|||||||
* Reloads current event
|
* Reloads current event
|
||||||
*/
|
*/
|
||||||
reload() {
|
reload() {
|
||||||
if (state.runtime.selectedEventId) {
|
if (state.eventNow) {
|
||||||
stateMutations.reload();
|
stateMutations.reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -313,7 +313,7 @@ class RuntimeService {
|
|||||||
logger.warning(LogOrigin.Server, `Roll: ${error}`);
|
logger.warning(LogOrigin.Server, `Roll: ${error}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newState = state.playback;
|
const newState = state.timer.playback;
|
||||||
logger.info(LogOrigin.Playback, `Play Mode ${newState.toUpperCase()}`);
|
logger.info(LogOrigin.Playback, `Play Mode ${newState.toUpperCase()}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,11 @@ export const normaliseEndTime = (start: number, end: number) => (end < start ? e
|
|||||||
* @returns {number | null} new current time or null if nothing is running
|
* @returns {number | null} new current time or null if nothing is running
|
||||||
*/
|
*/
|
||||||
export function getExpectedFinish(state: TState): MaybeNumber {
|
export function getExpectedFinish(state: TState): MaybeNumber {
|
||||||
const { startedAt, clock, finishedAt, duration, addedTime, timerType, pausedAt } = state.timer;
|
const { startedAt, finishedAt, duration, addedTime } = state.timer;
|
||||||
|
const { timerType } = state.eventNow;
|
||||||
|
const { pausedAt } = state._timer;
|
||||||
const { timeEnd } = state.eventNow;
|
const { timeEnd } = state.eventNow;
|
||||||
|
const { clock } = state;
|
||||||
|
|
||||||
if (startedAt === null) {
|
if (startedAt === null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -47,8 +50,11 @@ export function getExpectedFinish(state: TState): MaybeNumber {
|
|||||||
* @returns {number} current time for timer
|
* @returns {number} current time for timer
|
||||||
*/
|
*/
|
||||||
export function getCurrent(state: TState): number {
|
export function getCurrent(state: TState): number {
|
||||||
const { startedAt, duration, addedTime, clock, timerType, pausedAt } = state.timer;
|
const { startedAt, duration, addedTime } = state.timer;
|
||||||
|
const { timerType } = state.eventNow;
|
||||||
|
const { pausedAt } = state._timer;
|
||||||
const { timeEnd } = state.eventNow;
|
const { timeEnd } = state.eventNow;
|
||||||
|
const { clock } = state;
|
||||||
|
|
||||||
if (timerType === TimerType.TimeToEnd) {
|
if (timerType === TimerType.TimeToEnd) {
|
||||||
const isNextDay = startedAt > timeEnd;
|
const isNextDay = startedAt > timeEnd;
|
||||||
@@ -77,7 +83,9 @@ export function getCurrent(state: TState): number {
|
|||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function skippedOutOfEvent(state: TState, previousTime: number, skipLimit: number): boolean {
|
export function skippedOutOfEvent(state: TState, previousTime: number, skipLimit: number): boolean {
|
||||||
const { clock, startedAt, expectedFinish } = state.timer;
|
const { startedAt, expectedFinish } = state.timer;
|
||||||
|
const { clock } = state;
|
||||||
|
|
||||||
const hasPassedMidnight = previousTime > dayInMs - skipLimit && clock < skipLimit;
|
const hasPassedMidnight = previousTime > dayInMs - skipLimit && clock < skipLimit;
|
||||||
const adjustedClock = hasPassedMidnight ? clock + dayInMs : clock;
|
const adjustedClock = hasPassedMidnight ? clock + dayInMs : clock;
|
||||||
|
|
||||||
@@ -224,8 +232,10 @@ export const getRollTimers = (rundown: OntimeEvent[], timeNow: number) => {
|
|||||||
* @returns object with selection variables
|
* @returns object with selection variables
|
||||||
*/
|
*/
|
||||||
export const updateRoll = (state: TState) => {
|
export const updateRoll = (state: TState) => {
|
||||||
const { selectedEventId } = state.runtime;
|
const { current, expectedFinish, startedAt, secondaryTimer } = state.timer;
|
||||||
const { current, expectedFinish, startedAt, clock, secondaryTimer, secondaryTarget } = state.timer;
|
const { secondaryTarget } = state._timer;
|
||||||
|
const { clock } = state;
|
||||||
|
const selectedEventId = state.eventNow?.id ?? null;
|
||||||
|
|
||||||
// timers
|
// timers
|
||||||
let updatedTimer = current;
|
let updatedTimer = current;
|
||||||
|
|||||||
+60
-102
@@ -25,38 +25,31 @@ const timeSkipLimit = 1000;
|
|||||||
|
|
||||||
const initialRuntime: Runtime = {
|
const initialRuntime: Runtime = {
|
||||||
selectedEventIndex: null,
|
selectedEventIndex: null,
|
||||||
selectedEventId: null, // TODO: remove
|
|
||||||
selectedPublicEventId: null, // TODO: remove
|
|
||||||
nextEventId: null, // TODO: remove
|
|
||||||
nextPublicEventId: null, // TODO: remove
|
|
||||||
numEvents: 0,
|
numEvents: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialTimer: TimerState = {
|
const initialTimer: TimerState = {
|
||||||
clock: clock.timeNow(),
|
addedTime: 0,
|
||||||
current: null,
|
current: null,
|
||||||
|
duration: null,
|
||||||
elapsed: null,
|
elapsed: null,
|
||||||
expectedFinish: null, // TODO: expected finish could account for midnight, we cleanup in the clients
|
expectedFinish: null, // TODO: expected finish could account for midnight, we cleanup in the clients
|
||||||
addedTime: 0,
|
|
||||||
startedAt: null,
|
|
||||||
finishedAt: null,
|
finishedAt: null,
|
||||||
|
playback: Playback.Stop,
|
||||||
secondaryTimer: null,
|
secondaryTimer: null,
|
||||||
duration: null,
|
startedAt: null,
|
||||||
timerType: null, // TODO: remove
|
|
||||||
endAction: null, // TODO: remove
|
|
||||||
timeWarning: null, // TODO: remove
|
|
||||||
timeDanger: null, // TODO: remove
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TState = DeepReadonly<{
|
export type TState = DeepReadonly<{
|
||||||
|
clock: number; // realtime clock
|
||||||
eventNow: OntimeEvent | null;
|
eventNow: OntimeEvent | null;
|
||||||
publicEventNow: OntimeEvent | null;
|
publicEventNow: OntimeEvent | null;
|
||||||
eventNext: OntimeEvent | null;
|
eventNext: OntimeEvent | null;
|
||||||
publicEventNext: OntimeEvent | null;
|
publicEventNext: OntimeEvent | null;
|
||||||
runtime: Runtime;
|
runtime: Runtime;
|
||||||
playback: Playback; // TODO: merge into timer?
|
timer: TimerState;
|
||||||
// TODO: these are private state and should not be emitted
|
// private properties of the timer calculations
|
||||||
timer: TimerState & {
|
_timer: {
|
||||||
pausedAt: MaybeNumber;
|
pausedAt: MaybeNumber;
|
||||||
finishedNow: boolean;
|
finishedNow: boolean;
|
||||||
lastUpdate: MaybeNumber;
|
lastUpdate: MaybeNumber;
|
||||||
@@ -65,14 +58,14 @@ export type TState = DeepReadonly<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
export const state: TState = {
|
export const state: TState = {
|
||||||
|
clock: clock.timeNow(),
|
||||||
eventNow: null,
|
eventNow: null,
|
||||||
publicEventNow: null,
|
publicEventNow: null,
|
||||||
eventNext: null,
|
eventNext: null,
|
||||||
publicEventNext: null,
|
publicEventNext: null,
|
||||||
runtime: initialRuntime,
|
runtime: initialRuntime,
|
||||||
playback: Playback.Stop, // TODO: merge into timer?
|
timer: { ...initialTimer },
|
||||||
timer: {
|
_timer: {
|
||||||
...initialTimer,
|
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
lastUpdate: null,
|
lastUpdate: null,
|
||||||
secondaryTarget: null,
|
secondaryTarget: null,
|
||||||
@@ -90,22 +83,16 @@ export const stateMutations = {
|
|||||||
const eventIndex = rundown.findIndex((eventInMemory) => eventInMemory.id === event.id);
|
const eventIndex = rundown.findIndex((eventInMemory) => eventInMemory.id === event.id);
|
||||||
|
|
||||||
state.runtime.selectedEventIndex = eventIndex;
|
state.runtime.selectedEventIndex = eventIndex;
|
||||||
state.runtime.selectedEventId = event.id;
|
|
||||||
state.runtime.numEvents = rundown.length;
|
state.runtime.numEvents = rundown.length;
|
||||||
|
|
||||||
this.loadNow(event, rundown);
|
this.loadNow(event, rundown);
|
||||||
this.loadNext(rundown);
|
this.loadNext(rundown);
|
||||||
|
|
||||||
state.timer.clock = clock.timeNow();
|
state.clock = clock.timeNow();
|
||||||
state.playback = Playback.Armed;
|
state.timer.playback = Playback.Armed;
|
||||||
state.timer.duration = calculateDuration(event.timeStart, event.timeEnd);
|
state.timer.duration = calculateDuration(event.timeStart, event.timeEnd);
|
||||||
state.timer.current = getCurrent(state);
|
state.timer.current = getCurrent(state);
|
||||||
|
|
||||||
state.timer.timerType = event.timerType;
|
|
||||||
state.timer.endAction = event.endAction;
|
|
||||||
state.timer.timeWarning = event.timeWarning;
|
|
||||||
state.timer.timeDanger = event.timeDanger;
|
|
||||||
|
|
||||||
if (initialData) {
|
if (initialData) {
|
||||||
stateMutations.timer.patch(initialData);
|
stateMutations.timer.patch(initialData);
|
||||||
}
|
}
|
||||||
@@ -118,11 +105,9 @@ export const stateMutations = {
|
|||||||
// check if current is also public
|
// check if current is also public
|
||||||
if (event.isPublic) {
|
if (event.isPublic) {
|
||||||
state.publicEventNow = event;
|
state.publicEventNow = event;
|
||||||
state.runtime.selectedPublicEventId = event.id;
|
|
||||||
} else {
|
} else {
|
||||||
// assume there is no public event
|
// assume there is no public event
|
||||||
state.publicEventNow = null;
|
state.publicEventNow = null;
|
||||||
state.runtime.selectedPublicEventId = null;
|
|
||||||
|
|
||||||
// if there is nothing before, return
|
// if there is nothing before, return
|
||||||
if (!state.runtime.selectedEventIndex) {
|
if (!state.runtime.selectedEventIndex) {
|
||||||
@@ -133,7 +118,6 @@ export const stateMutations = {
|
|||||||
for (let i = state.runtime.selectedEventIndex; i >= 0; i--) {
|
for (let i = state.runtime.selectedEventIndex; i >= 0; i--) {
|
||||||
if (playableEvents[i].isPublic) {
|
if (playableEvents[i].isPublic) {
|
||||||
state.publicEventNow = playableEvents[i];
|
state.publicEventNow = playableEvents[i];
|
||||||
state.runtime.selectedPublicEventId = playableEvents[i].id;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,8 +129,6 @@ export const stateMutations = {
|
|||||||
// assume there are no next events
|
// assume there are no next events
|
||||||
state.eventNext = null;
|
state.eventNext = null;
|
||||||
state.publicEventNext = null;
|
state.publicEventNext = null;
|
||||||
state.runtime.nextEventId = null;
|
|
||||||
state.runtime.nextPublicEventId = null;
|
|
||||||
|
|
||||||
if (state.runtime.selectedEventIndex === null) {
|
if (state.runtime.selectedEventIndex === null) {
|
||||||
return;
|
return;
|
||||||
@@ -162,14 +144,12 @@ export const stateMutations = {
|
|||||||
// if we have not set private
|
// if we have not set private
|
||||||
if (!nextProduction) {
|
if (!nextProduction) {
|
||||||
state.eventNext = playableEvents[i];
|
state.eventNext = playableEvents[i];
|
||||||
state.runtime.nextEventId = playableEvents[i].id;
|
|
||||||
nextProduction = true;
|
nextProduction = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if event is public
|
// if event is public
|
||||||
if (playableEvents[i].isPublic) {
|
if (playableEvents[i].isPublic) {
|
||||||
state.publicEventNext = playableEvents[i];
|
state.publicEventNext = playableEvents[i];
|
||||||
state.runtime.nextPublicEventId = playableEvents[i].id;
|
|
||||||
nextPublic = true;
|
nextPublic = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,14 +160,8 @@ export const stateMutations = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
resume(restorePoint: RestorePoint, event: OntimeEvent, rundown: OntimeEvent[]) {
|
resume(restorePoint: RestorePoint, event: OntimeEvent, rundown: OntimeEvent[]) {
|
||||||
mutate((state) => {
|
mutate((_state) => {
|
||||||
const { playback, ...patch } = restorePoint;
|
stateMutations.load(event, rundown, restorePoint);
|
||||||
|
|
||||||
// TODO: this.load gets typed as any?
|
|
||||||
stateMutations.load(event, rundown, patch);
|
|
||||||
|
|
||||||
// TODO: send as part of the patch when playback is merged to timer
|
|
||||||
state.playback = playback;
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@@ -202,21 +176,17 @@ export const stateMutations = {
|
|||||||
// update data which is duplicate between eventNow and timer objects
|
// update data which is duplicate between eventNow and timer objects
|
||||||
state.timer.duration = calculateDuration(state.eventNow.timeStart, state.eventNow.timeEnd);
|
state.timer.duration = calculateDuration(state.eventNow.timeStart, state.eventNow.timeEnd);
|
||||||
state.timer.expectedFinish = getExpectedFinish(state);
|
state.timer.expectedFinish = getExpectedFinish(state);
|
||||||
state.timer.timerType = state.eventNow.timerType;
|
|
||||||
state.timer.endAction = state.eventNow.endAction;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state.playback = Playback.Armed;
|
state.timer.playback = Playback.Armed;
|
||||||
|
|
||||||
state.timer.duration = calculateDuration(state.eventNow.timeStart, state.eventNow.timeEnd);
|
state.timer.duration = calculateDuration(state.eventNow.timeStart, state.eventNow.timeEnd);
|
||||||
state.timer.current = state.timer.duration;
|
state.timer.current = state.timer.duration;
|
||||||
state.timer.elapsed = null;
|
state.timer.elapsed = null;
|
||||||
state.timer.timerType = state.eventNow.timerType;
|
|
||||||
state.timer.endAction = state.eventNow.endAction;
|
|
||||||
|
|
||||||
state.timer.startedAt = null;
|
state.timer.startedAt = null;
|
||||||
state.timer.finishedAt = null;
|
state.timer.finishedAt = null;
|
||||||
state.timer.pausedAt = null;
|
state._timer.pausedAt = null;
|
||||||
state.timer.addedTime = 0;
|
state.timer.addedTime = 0;
|
||||||
|
|
||||||
state.timer.expectedFinish = getExpectedFinish(state);
|
state.timer.expectedFinish = getExpectedFinish(state);
|
||||||
@@ -242,11 +212,10 @@ export const stateMutations = {
|
|||||||
// TODO: could we avoid having this dependency?
|
// TODO: could we avoid having this dependency?
|
||||||
state.runtime.numEvents = EventLoader.getPlayableEvents().length;
|
state.runtime.numEvents = EventLoader.getPlayableEvents().length;
|
||||||
|
|
||||||
state.playback = Playback.Stop;
|
state.timer.playback = Playback.Stop;
|
||||||
|
state.clock = clock.timeNow();
|
||||||
state.timer = {
|
state.timer = { ...initialTimer };
|
||||||
...initialTimer,
|
state._timer = {
|
||||||
clock: clock.timeNow(),
|
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
lastUpdate: null,
|
lastUpdate: null,
|
||||||
secondaryTarget: null,
|
secondaryTarget: null,
|
||||||
@@ -267,22 +236,22 @@ export const stateMutations = {
|
|||||||
start() {
|
start() {
|
||||||
mutate(
|
mutate(
|
||||||
(state) => {
|
(state) => {
|
||||||
state.timer.clock = clock.timeNow();
|
state.clock = clock.timeNow();
|
||||||
state.timer.secondaryTimer = null;
|
state.timer.secondaryTimer = null;
|
||||||
state.timer.secondaryTarget = null;
|
state._timer.secondaryTarget = null;
|
||||||
|
|
||||||
// add paused time if it exists
|
// add paused time if it exists
|
||||||
if (state.timer.pausedAt) {
|
if (state._timer.pausedAt) {
|
||||||
const timeToAdd = state.timer.clock - state.timer.pausedAt;
|
const timeToAdd = state.clock - state._timer.pausedAt;
|
||||||
state.timer.addedTime += timeToAdd;
|
state.timer.addedTime += timeToAdd;
|
||||||
state.timer.pausedAt = null;
|
state._timer.pausedAt = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.timer.startedAt === null) {
|
if (state.timer.startedAt === null) {
|
||||||
state.timer.startedAt = state.timer.clock;
|
state.timer.startedAt = state.clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.playback = Playback.Play;
|
state.timer.playback = Playback.Play;
|
||||||
state.timer.expectedFinish = getExpectedFinish(state);
|
state.timer.expectedFinish = getExpectedFinish(state);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -307,13 +276,13 @@ export const stateMutations = {
|
|||||||
pause() {
|
pause() {
|
||||||
mutate(
|
mutate(
|
||||||
(state) => {
|
(state) => {
|
||||||
if (state.playback !== Playback.Play) {
|
if (state.timer.playback !== Playback.Play) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.playback = Playback.Pause;
|
state.timer.playback = Playback.Pause;
|
||||||
state.timer.clock = clock.timeNow();
|
state.clock = clock.timeNow();
|
||||||
state.timer.pausedAt = state.timer.clock;
|
state._timer.pausedAt = state.clock;
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -327,24 +296,18 @@ export const stateMutations = {
|
|||||||
},
|
},
|
||||||
resume(event: OntimeEvent, restorePoint: RestorePoint) {
|
resume(event: OntimeEvent, restorePoint: RestorePoint) {
|
||||||
mutate((state) => {
|
mutate((state) => {
|
||||||
state.timer.clock = clock.timeNow();
|
state.clock = clock.timeNow();
|
||||||
|
|
||||||
// TODO: the duplication of timer data would not be necessary
|
|
||||||
// once event loader is merged here
|
|
||||||
state.runtime.selectedEventId = event.id;
|
|
||||||
state.timer.startedAt = restorePoint.startedAt;
|
state.timer.startedAt = restorePoint.startedAt;
|
||||||
state.timer.duration = calculateDuration(event.timeStart, event.timeEnd);
|
state.timer.duration = calculateDuration(event.timeStart, event.timeEnd);
|
||||||
state.timer.current = state.timer.duration;
|
state.timer.current = state.timer.duration;
|
||||||
|
|
||||||
state.timer.timerType = event.timerType;
|
state.timer.playback = restorePoint.playback;
|
||||||
state.timer.endAction = event.endAction;
|
state._timer.pausedAt = restorePoint.pausedAt;
|
||||||
|
|
||||||
state.playback = restorePoint.playback;
|
|
||||||
state.timer.pausedAt = restorePoint.pausedAt;
|
|
||||||
state.timer.addedTime = restorePoint.addedTime;
|
state.timer.addedTime = restorePoint.addedTime;
|
||||||
|
|
||||||
// check if event finished meanwhile
|
// check if event finished meanwhile
|
||||||
if (state.timer.timerType === TimerType.TimeToEnd) {
|
if (event.timerType === TimerType.TimeToEnd) {
|
||||||
state.timer.current = getCurrent(state);
|
state.timer.current = getCurrent(state);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -388,10 +351,6 @@ export const stateMutations = {
|
|||||||
state.timer.secondaryTimer = updatedSecondaryTimer;
|
state.timer.secondaryTimer = updatedSecondaryTimer;
|
||||||
state.timer.elapsed = state.timer.duration - state.timer.current;
|
state.timer.elapsed = state.timer.duration - state.timer.current;
|
||||||
|
|
||||||
if (isFinished) {
|
|
||||||
state.runtime.selectedEventId = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { doRoll: doRollLoad, isFinished };
|
return { doRoll: doRollLoad, isFinished };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,8 +358,8 @@ export const stateMutations = {
|
|||||||
let isFinished = false;
|
let isFinished = false;
|
||||||
state.timer.current = getCurrent(state);
|
state.timer.current = getCurrent(state);
|
||||||
|
|
||||||
if (state.playback === Playback.Play && state.timer.finishedNow) {
|
if (state.timer.playback === Playback.Play && state._timer.finishedNow) {
|
||||||
state.timer.finishedAt = state.timer.clock;
|
state.timer.finishedAt = state.clock;
|
||||||
isFinished = true;
|
isFinished = true;
|
||||||
} else {
|
} else {
|
||||||
state.timer.expectedFinish = getExpectedFinish(state);
|
state.timer.expectedFinish = getExpectedFinish(state);
|
||||||
@@ -419,16 +378,16 @@ export const stateMutations = {
|
|||||||
let _isFinished = false;
|
let _isFinished = false;
|
||||||
let _shouldNotify = false;
|
let _shouldNotify = false;
|
||||||
|
|
||||||
const previousTime = state.timer.clock;
|
const previousTime = state.clock;
|
||||||
state.timer.clock = clock.timeNow();
|
state.clock = clock.timeNow();
|
||||||
const hasSkippedBack = previousTime > state.timer.clock;
|
const hasSkippedBack = previousTime > state.clock;
|
||||||
|
|
||||||
if (hasSkippedBack) {
|
if (hasSkippedBack) {
|
||||||
_force = true;
|
_force = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we call integrations if we update timers
|
// we call integrations if we update timers
|
||||||
if (state.playback === Playback.Roll) {
|
if (state.timer.playback === Playback.Roll) {
|
||||||
const result = roll();
|
const result = roll();
|
||||||
_shouldNotify = true;
|
_shouldNotify = true;
|
||||||
_doRoll = result.doRoll;
|
_doRoll = result.doRoll;
|
||||||
@@ -442,9 +401,9 @@ export const stateMutations = {
|
|||||||
|
|
||||||
// we only update the store at the updateInterval
|
// we only update the store at the updateInterval
|
||||||
// side effects such as onFinish will still be triggered in the update functions
|
// side effects such as onFinish will still be triggered in the update functions
|
||||||
const isTimeToUpdate = state.timer.clock > state.timer.lastUpdate + updateInterval;
|
const isTimeToUpdate = state.clock > state._timer.lastUpdate + updateInterval;
|
||||||
if (_force || isTimeToUpdate) {
|
if (_force || isTimeToUpdate) {
|
||||||
state.timer.lastUpdate = state.timer.clock;
|
state._timer.lastUpdate = state.clock;
|
||||||
// TODO: can we simplify the didUpdate and shouldNotify
|
// TODO: can we simplify the didUpdate and shouldNotify
|
||||||
_didUpdate = true;
|
_didUpdate = true;
|
||||||
}
|
}
|
||||||
@@ -471,13 +430,13 @@ export const stateMutations = {
|
|||||||
integrationService.dispatch(TimerLifeCycle.onFinish);
|
integrationService.dispatch(TimerLifeCycle.onFinish);
|
||||||
|
|
||||||
// handle end action if there was a timer playing
|
// handle end action if there was a timer playing
|
||||||
if (newState.playback === Playback.Play) {
|
if (newState.timer.playback === Playback.Play) {
|
||||||
if (newState.timer.endAction === EndAction.Stop) {
|
if (newState.eventNow.endAction === EndAction.Stop) {
|
||||||
runtimeService.stop();
|
runtimeService.stop();
|
||||||
} else if (newState.timer.endAction === EndAction.LoadNext) {
|
} else if (newState.eventNow.endAction === EndAction.LoadNext) {
|
||||||
// we need to delay here to put this action in the queue stack. otherwise it won't be executed properly
|
// we need to delay here to put this action in the queue stack. otherwise it won't be executed properly
|
||||||
setTimeout(runtimeService.loadNext, 0);
|
setTimeout(runtimeService.loadNext, 0);
|
||||||
} else if (newState.timer.endAction === EndAction.PlayNext) {
|
} else if (newState.eventNow.endAction === EndAction.PlayNext) {
|
||||||
runtimeService.startNext();
|
runtimeService.startNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -490,12 +449,12 @@ export const stateMutations = {
|
|||||||
mutate((state) => {
|
mutate((state) => {
|
||||||
stateMutations.timer.clear();
|
stateMutations.timer.clear();
|
||||||
|
|
||||||
const { nextEvent, currentEvent } = getRollTimers(rundown, state.timer.clock);
|
const { nextEvent, currentEvent } = getRollTimers(rundown, state.clock);
|
||||||
|
|
||||||
if (currentEvent) {
|
if (currentEvent) {
|
||||||
// there is something running, load
|
// there is something running, load
|
||||||
state.timer.secondaryTimer = null;
|
state.timer.secondaryTimer = null;
|
||||||
state.timer.secondaryTarget = null;
|
state._timer.secondaryTarget = null;
|
||||||
|
|
||||||
// account for event that finishes the day after
|
// account for event that finishes the day after
|
||||||
const endTime =
|
const endTime =
|
||||||
@@ -506,17 +465,16 @@ export const stateMutations = {
|
|||||||
stateMutations.load(currentEvent, rundown, {
|
stateMutations.load(currentEvent, rundown, {
|
||||||
startedAt: currentEvent.timeStart,
|
startedAt: currentEvent.timeStart,
|
||||||
expectedFinish: currentEvent.timeEnd,
|
expectedFinish: currentEvent.timeEnd,
|
||||||
current: endTime - state.timer.clock,
|
current: endTime - state.clock,
|
||||||
});
|
});
|
||||||
} else if (nextEvent) {
|
} else if (nextEvent) {
|
||||||
// account for day after
|
// account for day after
|
||||||
const nextStart =
|
const nextStart = nextEvent.timeStart < state.clock ? nextEvent.timeStart + dayInMs : nextEvent.timeStart;
|
||||||
nextEvent.timeStart < state.timer.clock ? nextEvent.timeStart + dayInMs : nextEvent.timeStart;
|
|
||||||
// nothing now, but something coming up
|
// nothing now, but something coming up
|
||||||
state.timer.secondaryTimer = nextStart - state.timer.clock;
|
state.timer.secondaryTimer = nextStart - state.clock;
|
||||||
state.timer.secondaryTarget = nextStart;
|
state._timer.secondaryTarget = nextStart;
|
||||||
}
|
}
|
||||||
state.playback = Playback.Roll;
|
state.timer.playback = Playback.Roll;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -559,22 +517,22 @@ export function mutate<R>(
|
|||||||
// set eventStore any time a mutation happens
|
// set eventStore any time a mutation happens
|
||||||
// this means we are pushing this data to the client every 32ms
|
// this means we are pushing this data to the client every 32ms
|
||||||
eventStore.batchSet({
|
eventStore.batchSet({
|
||||||
|
clock: newState.clock,
|
||||||
eventNow: newState.eventNow,
|
eventNow: newState.eventNow,
|
||||||
publicEventNow: newState.publicEventNow,
|
publicEventNow: newState.publicEventNow,
|
||||||
eventNext: newState.eventNext,
|
eventNext: newState.eventNext,
|
||||||
publicEventNext: newState.publicEventNext,
|
publicEventNext: newState.publicEventNext,
|
||||||
loaded: newState.runtime, // TODO: rename to runtime
|
runtime: newState.runtime,
|
||||||
playback: newState.playback,
|
|
||||||
timer: newState.timer,
|
timer: newState.timer,
|
||||||
});
|
});
|
||||||
|
|
||||||
// we write to restore service if the underlying data changes
|
// we write to restore service if the underlying data changes
|
||||||
restoreService.save({
|
restoreService.save({
|
||||||
playback: state.playback,
|
playback: state.timer.playback,
|
||||||
selectedEventId: state.runtime.selectedEventId,
|
selectedEventId: state.eventNow?.id ?? null,
|
||||||
startedAt: state.timer.startedAt,
|
startedAt: state.timer.startedAt,
|
||||||
addedTime: state.timer.addedTime,
|
addedTime: state.timer.addedTime,
|
||||||
pausedAt: state.timer.pausedAt,
|
pausedAt: state._timer.pausedAt,
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
|
import { MaybeNumber } from '../../utils/utils.type.js';
|
||||||
|
|
||||||
export type Runtime = {
|
export type Runtime = {
|
||||||
numEvents: number;
|
numEvents: number;
|
||||||
selectedEventIndex: number | null;
|
selectedEventIndex: MaybeNumber;
|
||||||
selectedEventId: string | null;
|
|
||||||
selectedPublicEventId: string | null;
|
|
||||||
nextEventId: string | null;
|
|
||||||
nextPublicEventId: string | null;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
import { Playback } from './Playback.type.js';
|
|
||||||
import { MessageState } from './MessageControl.type.js';
|
import { MessageState } from './MessageControl.type.js';
|
||||||
import { TimerState } from './TimerState.type.js';
|
import { TimerState } from './TimerState.type.js';
|
||||||
import { Runtime } from './Runtime.type.js';
|
import { Runtime } from './Runtime.type.js';
|
||||||
import { OntimeEvent } from '../core/OntimeEvent.type.js';
|
import { OntimeEvent } from '../core/OntimeEvent.type.js';
|
||||||
|
|
||||||
export type RuntimeStore = {
|
export type RuntimeStore = {
|
||||||
// timer service
|
// timer data
|
||||||
|
clock: number;
|
||||||
timer: TimerState;
|
timer: TimerState;
|
||||||
playback: Playback;
|
onAir: boolean;
|
||||||
|
|
||||||
// messages service
|
// messages service
|
||||||
message: MessageState;
|
message: MessageState;
|
||||||
onAir: boolean;
|
|
||||||
|
|
||||||
// event loader
|
// rundown data
|
||||||
loaded: Runtime;
|
runtime: Runtime;
|
||||||
eventNow: OntimeEvent | null;
|
eventNow: OntimeEvent | null;
|
||||||
publicEventNow: OntimeEvent | null;
|
publicEventNow: OntimeEvent | null;
|
||||||
eventNext: OntimeEvent | null;
|
eventNext: OntimeEvent | null;
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
import { TimerType } from '../TimerType.type.js';
|
import { MaybeNumber } from '../../index.js';
|
||||||
import { EndAction } from '../EndAction.type.js';
|
import { Playback } from './Playback.type.js';
|
||||||
|
|
||||||
export type TimerState = {
|
export type TimerState = {
|
||||||
clock: number; // realtime clock
|
|
||||||
current: number | null; // running countdown
|
|
||||||
elapsed: number | null; // elapsed time in current timer
|
|
||||||
expectedFinish: number | null;
|
|
||||||
addedTime: number; // time added by user, can be negative
|
addedTime: number; // time added by user, can be negative
|
||||||
startedAt: number | null;
|
current: MaybeNumber; // running countdown
|
||||||
finishedAt: number | null; // only if timer has already finished
|
duration: MaybeNumber; // normalised duration of current event
|
||||||
secondaryTimer: number | null; // used for roll mode
|
elapsed: MaybeNumber; // elapsed time in current timer
|
||||||
duration: number | null;
|
expectedFinish: MaybeNumber; // time we expect timer to finish
|
||||||
timerType: TimerType | null;
|
finishedAt: MaybeNumber; // only if timer has already finished
|
||||||
endAction: EndAction | null;
|
playback: Playback;
|
||||||
timeWarning: number | null;
|
secondaryTimer: MaybeNumber; // used for roll mode
|
||||||
timeDanger: number | null;
|
startedAt: MaybeNumber; // only if timer has already started
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user