refactor: show projected time

This commit is contained in:
Carlos Valente
2025-02-16 22:06:08 +01:00
committed by Carlos Valente
parent 9c41f8ff6b
commit a5afb32b8a
4 changed files with 118 additions and 25 deletions
@@ -170,6 +170,10 @@ export const useTimelineStatus = createSelector((state: RuntimeStore) => ({
offset: state.runtime.offset, offset: state.runtime.offset,
})); }));
export const useRuntimeOffset = createSelector((state: RuntimeStore) => ({
offset: state.runtime.offset,
}));
export const usePing = createSelector((state: RuntimeStore) => ({ export const usePing = createSelector((state: RuntimeStore) => ({
ping: state.ping, ping: state.ping,
})); }));
@@ -49,6 +49,14 @@ $indeterminate-width: clamp(32px, 3vw, 48px);
&--delay { &--delay {
color: $ontime-delay-text; color: $ontime-delay-text;
} }
&--ahead {
color: $green-500;
}
&--behind {
color: $orange-500;
}
} }
.entry-title { .entry-title {
@@ -1,7 +1,10 @@
import { useRuntimeOffset } from '../../../common/hooks/useSocket';
import { cx } from '../../../common/utils/styleUtils'; import { cx } from '../../../common/utils/styleUtils';
import { formatTime } from '../../../common/utils/time'; import { formatTime } from '../../../common/utils/time';
import SuperscriptTime from '../../../features/viewers/common/superscript-time/SuperscriptTime'; import SuperscriptTime from '../../../features/viewers/common/superscript-time/SuperscriptTime';
import { useScheduleOptions } from './schedule.options';
import './Schedule.scss'; import './Schedule.scss';
const formatOptions = { const formatOptions = {
@@ -21,36 +24,38 @@ interface ScheduleItemProps {
export default function ScheduleItem(props: ScheduleItemProps) { export default function ScheduleItem(props: ScheduleItemProps) {
const { timeStart, timeEnd, title, backstageEvent, colour, skip, delay } = props; const { timeStart, timeEnd, title, backstageEvent, colour, skip, delay } = props;
const { showProjected } = useScheduleOptions();
const start = formatTime(timeStart, formatOptions); if (showProjected) {
const end = formatTime(timeEnd, formatOptions);
if (delay > 0) {
const delayedStart = formatTime(timeStart + delay, formatOptions);
const delayedEnd = formatTime(timeEnd + delay, formatOptions);
return ( return (
<li className={cx(['entry', skip && 'entry--skip'])}> <ProjectedScheduleItem
<div className='entry-times'> timeStart={timeStart}
<span className='entry-times--delayed'> timeEnd={timeEnd}
<span className='entry-colour' style={{ backgroundColor: colour }} /> title={title}
<SuperscriptTime time={start} /> colour={colour}
backstageEvent={backstageEvent}
<SuperscriptTime time={end} /> skip={skip}
{backstageEvent && '*'} delay={delay}
</span> />
<span className='entry-times--delay'>
<SuperscriptTime time={delayedStart} />
<SuperscriptTime time={delayedEnd} />
{backstageEvent && '*'}
</span>
</div>
<div className='entry-title'>{title}</div>
</li>
); );
} }
if (delay > 0) {
return (
<DelayedScheduleItem
timeStart={timeStart}
timeEnd={timeEnd}
title={title}
colour={colour}
backstageEvent={backstageEvent}
skip={skip}
delay={delay}
/>
);
}
const start = formatTime(timeStart, formatOptions);
const end = formatTime(timeEnd, formatOptions);
return ( return (
<li className={cx(['entry', skip && 'entry--skip'])}> <li className={cx(['entry', skip && 'entry--skip'])}>
<div className='entry-times'> <div className='entry-times'>
@@ -64,3 +69,70 @@ export default function ScheduleItem(props: ScheduleItemProps) {
</li> </li>
); );
} }
function DelayedScheduleItem(props: ScheduleItemProps) {
const { timeStart, timeEnd, title, backstageEvent, colour, skip, delay } = props;
const start = formatTime(timeStart, formatOptions);
const end = formatTime(timeEnd, formatOptions);
const delayedStart = formatTime(timeStart + delay, formatOptions);
const delayedEnd = formatTime(timeEnd + delay, formatOptions);
return (
<li className={cx(['entry', skip && 'entry--skip'])}>
<div className='entry-times'>
<span className='entry-times--delayed'>
<span className='entry-colour' style={{ backgroundColor: colour }} />
<SuperscriptTime time={start} />
<SuperscriptTime time={end} />
{backstageEvent && '*'}
</span>
<span className='entry-times--delay'>
<SuperscriptTime time={delayedStart} />
<SuperscriptTime time={delayedEnd} />
{backstageEvent && '*'}
</span>
</div>
<div className='entry-title'>{title}</div>
</li>
);
}
function ProjectedScheduleItem(props: ScheduleItemProps) {
const { timeStart, timeEnd, title, backstageEvent, colour, skip, delay } = props;
return (
<li className={cx(['entry', skip && 'entry--skip'])}>
<div className='entry-times'>
<span className='entry-colour' style={{ backgroundColor: colour }} />
<ProjectedTime time={timeStart} delay={delay} />
<ProjectedTime time={timeEnd} delay={delay} />
{backstageEvent && '*'}
</div>
<div className='entry-title'>{title}</div>
</li>
);
}
interface OffsetTimeProps {
time: number;
delay: number;
}
function ProjectedTime(props: OffsetTimeProps) {
const { time, delay } = props;
const { offset } = useRuntimeOffset();
const projectedOffset = offset - delay;
const projectedTime = formatTime(time - offset, formatOptions);
return (
<SuperscriptTime
className={cx([projectedOffset > 0 && 'entry-times--ahead', projectedOffset < 0 && 'entry-times--behind'])}
time={projectedTime}
/>
);
}
@@ -23,18 +23,27 @@ export const scheduleOptions: ViewOption = {
type: 'number', type: 'number',
defaultValue: 10, defaultValue: 10,
}, },
{
id: 'showProjected',
title: 'Show projected time',
description: 'Whether scheduled times should account for runtime offset.',
type: 'boolean',
defaultValue: false,
},
], ],
}; };
type ScheduleOptions = { type ScheduleOptions = {
cycleInterval: number; cycleInterval: number;
stopCycle: boolean; stopCycle: boolean;
showProjected: boolean;
}; };
function getScheduleOptionsFromParams(searchParams: URLSearchParams): ScheduleOptions { function getScheduleOptionsFromParams(searchParams: URLSearchParams): ScheduleOptions {
return { return {
cycleInterval: Number(searchParams.get('cycleInterval')) || 10, cycleInterval: Number(searchParams.get('cycleInterval')) || 10,
stopCycle: isStringBoolean(searchParams.get('stopCycle')), stopCycle: isStringBoolean(searchParams.get('stopCycle')),
showProjected: isStringBoolean(searchParams.get('showProjected')),
}; };
} }