Files
ontime/apps/client/src/views/timer/timer.utils.ts
T
2026-02-16 06:58:08 +01:00

192 lines
5.0 KiB
TypeScript

import {
MaybeNumber,
MessageState,
OntimeEvent,
Playback,
RundownEntries,
TimerMessage,
TimerPhase,
TimerType,
} from 'ontime-types';
import { isPlaybackActive } from 'ontime-utils';
import { getFormattedTimer, getPropertyValue } from '../common/viewUtils';
/**
* Whether a message should be shown
*/
export function getShowMessage(message: TimerMessage): boolean {
return message.text !== '' && message.visible;
}
/**
* Whether the playback is playing
*/
export function getIsPlaying(playback: Playback): boolean {
return playback === Playback.Play || playback === Playback.Roll;
}
/**
* Gets the total time from the duration and added time of an event
*/
export function getTotalTime(duration: MaybeNumber, addedTime: MaybeNumber): number {
return (duration ?? 0) + (addedTime ?? 0);
}
/**
* Whether the progress bar should be shown for this timer type
*/
export function getShowProgressBar(timerType: TimerType) {
return timerType !== TimerType.None && timerType !== TimerType.Clock;
}
/**
* Whether the clock should be shown with this timer type
*/
export function getShowClock(timerType: TimerType) {
return timerType !== TimerType.Clock;
}
const fontSizeMap: { [key: number]: number } = {
4: 28, // 9:01
5: 28, // -9:01, 10:01, 9 min
6: 25, // -10:01, 10 min
8: 18, // 23:01:01
9: 18, // -23:01:01
};
/**
* Finds a font size that fits the timer in the screen
* Unfortunately hand tweaked
*/
export function getEstimatedFontSize(stageTimer: string, secondaryContent?: string): number {
const stageTimerCharacters = stageTimer.length;
let timerFontSize = (100 / (stageTimerCharacters - 1)) * 1.25;
if (fontSizeMap[stageTimerCharacters]) {
timerFontSize = fontSizeMap[stageTimerCharacters];
}
// we need to shrink the timer if the external is going to be there
// this number has been tweaked to fit in a landscape mobile screen
if (secondaryContent) {
timerFontSize *= 0.6;
}
return timerFontSize;
}
/**
* which, if any, modifier should be shown at any time
*/
export function getShowModifiers(
timerType: TimerType,
countToEnd: boolean,
phase: TimerPhase,
freezeOvertime: boolean,
freezeMessage: string,
hidePhase: boolean,
) {
if (hidePhase) {
return {
showEndMessage: false,
showFinished: false,
showWarning: false,
showDanger: false,
};
}
const showModifiers = timerType === TimerType.CountDown || countToEnd;
if (!showModifiers) {
return {
showEndMessage: false,
showFinished: false,
showWarning: false,
showDanger: false,
};
}
return {
showEndMessage: phase === TimerPhase.Overtime && freezeOvertime && freezeMessage !== '',
showFinished: phase === TimerPhase.Overtime,
showWarning: phase === TimerPhase.Warning,
showDanger: phase === TimerPhase.Danger,
};
}
/**
* What, if anything, should be displayed in the secondary field
*/
export function getSecondaryDisplay(
message: MessageState,
currentAux: MaybeNumber,
localisedMinutes: string,
removeSeconds: boolean,
removeLeadingZero: boolean,
hideSecondary: boolean,
): string | undefined {
if (hideSecondary) {
return;
}
if (
message.timer.secondarySource === 'aux1' ||
message.timer.secondarySource === 'aux2' ||
message.timer.secondarySource === 'aux3'
) {
return getFormattedTimer(currentAux, TimerType.CountDown, localisedMinutes, {
removeSeconds,
removeLeadingZero,
});
}
if (message.timer.secondarySource === 'secondary' && message.secondary) {
return message.secondary;
}
return;
}
/**
* What should we be showing in the cards?
*/
export function getCardData(
eventNow: OntimeEvent | null,
eventNext: OntimeEvent | null,
mainSource: keyof OntimeEvent | null | 'none',
secondarySource: keyof OntimeEvent | null | 'none',
playback: Playback,
phase: TimerPhase,
entries: RundownEntries,
) {
if (playback === Playback.Stop) {
return {
showNow: false,
nowMain: undefined,
nowSecondary: undefined,
showNext: false,
nextMain: undefined,
nextSecondary: undefined,
};
}
// pending roll timers would be classified as active
const hasActiveTimer = isPlaybackActive(playback) && phase !== TimerPhase.Pending;
// if we are loaded, we show the upcoming event as next
const nowMain = hasActiveTimer ? getPropertyValue(eventNow, mainSource ?? 'title') : undefined;
const nowSecondary = hasActiveTimer ? getPropertyValue(eventNow, secondarySource, entries) : undefined;
const nextMain = hasActiveTimer
? getPropertyValue(eventNext, mainSource ?? 'title')
: getPropertyValue(eventNow, mainSource ?? 'title');
const nextSecondary = hasActiveTimer
? getPropertyValue(eventNext, secondarySource, entries)
: getPropertyValue(eventNow, secondarySource, entries);
return {
showNow: mainSource !== 'none' && (Boolean(nowMain) || Boolean(nowSecondary)),
nowMain,
nowSecondary,
showNext: mainSource !== 'none' && (Boolean(nextMain) || Boolean(nextSecondary)),
nextMain,
nextSecondary,
};
}