import { useEffect } from 'react'; import { AnimatePresence, motion } from 'framer-motion'; import { Message, OntimeEvent, Playback, TimerMessage, TimerType, ViewSettings } from 'ontime-types'; import { overrideStylesURL } from '../../../common/api/apiConstants'; import MultiPartProgressBar from '../../../common/components/multi-part-progress-bar/MultiPartProgressBar'; import NavigationMenu from '../../../common/components/navigation-menu/NavigationMenu'; import TitleCard from '../../../common/components/title-card/TitleCard'; import { TIMER_OPTIONS } from '../../../common/components/view-params-editor/constants'; import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor'; import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet'; import { TimeManagerType } from '../../../common/models/TimeManager.type'; import { formatTime } from '../../../common/utils/time'; import { useTranslation } from '../../../translation/TranslationProvider'; import SuperscriptTime from '../common/superscript-time/SuperscriptTime'; import { formatTimerDisplay, getTimerByType } from '../common/viewerUtils'; import './Timer.scss'; const formatOptions = { showSeconds: true, format: 'hh:mm:ss a', }; // motion const titleVariants = { hidden: { x: -2500, }, visible: { x: 0, transition: { duration: 1, }, }, exit: { x: -2500, }, }; interface TimerProps { isMirrored: boolean; pres: TimerMessage; external: Message; eventNow: OntimeEvent | null; eventNext: OntimeEvent | null; time: TimeManagerType; viewSettings: ViewSettings; } export default function Timer(props: TimerProps) { const { isMirrored, pres, eventNow, eventNext, time, viewSettings, external } = props; const { shouldRender } = useRuntimeStylesheet(viewSettings?.overrideStyles && overrideStylesURL); const { getLocalizedString } = useTranslation(); useEffect(() => { document.title = 'ontime - Timer'; }, []); // defer rendering until we load stylesheets if (!shouldRender) { return null; } const clock = formatTime(time.clock, formatOptions); const showOverlay = pres.text !== '' && pres.visible; const isPlaying = time.playback !== Playback.Pause; const isNegative = (time.current ?? 0) < 0 && time.timerType !== TimerType.Clock && time.timerType !== TimerType.CountUp; const finished = time.playback === Playback.Play && (time.current ?? 0) < 0 && time.startedAt; const totalTime = (time.duration ?? 0) + (time.addedTime ?? 0); const showEndMessage = (time.current ?? 1) < 0 && viewSettings.endMessage; const showProgress = time.playback !== Playback.Stop; const showFinished = finished && (time.timerType !== TimerType.Clock || showEndMessage); const showWarning = (time.current ?? 1) < viewSettings.warningThreshold; const showDanger = (time.current ?? 1) < viewSettings.dangerThreshold; const showBlinking = pres.timerBlink; const showBlackout = pres.timerBlackout; const showClock = time.timerType !== TimerType.Clock; const showExternal = external.visible && external.text; const timerColor = showProgress && showDanger ? viewSettings.dangerColor : showProgress && showWarning ? viewSettings.warningColor : viewSettings.normalColor; const stageTimer = getTimerByType(time); let display = formatTimerDisplay(stageTimer); const stageTimerCharacters = display.replace('/:/g', '').length; if (isNegative) { display = `-${display}`; } const baseClasses = `stage-timer ${isMirrored ? 'mirror' : ''} ${showBlackout ? 'blackout' : ''}`; let timerFontSize = 89 / (stageTimerCharacters - 1); // we need to shrink the timer if the external is going to be there if (showExternal) { timerFontSize *= 0.8; } const externalFontSize = timerFontSize * 0.4 const timerContainerClasses = `timer-container ${showBlinking ? (showOverlay ? '' : 'blink') : ''}`; const timerClasses = `timer ${!isPlaying ? 'timer--paused' : ''} ${showFinished ? 'timer--finished' : ''}`; return (
{pres.text}
{getLocalizedString('common.time_now')}
{showEndMessage ? (
{viewSettings.endMessage}
) : (
{display}
)}
{external.text}
); }